home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-04-10 | 88.1 KB | 3,343 lines |
- Newsgroups: comp.sources.unix
- From: hyc@umix.cc.umich.edu (Howard Chu)
- Subject: v26i005: arc 5.21 (pl 8) - file archive/compression tool, Part02/03
- Sender: unix-sources-moderator@pa.dec.com
- Approved: vixie@pa.dec.com
-
- Submitted-By: hyc@umix.cc.umich.edu (Howard Chu)
- Posting-Number: Volume 26, Issue 5
- Archive-Name: arc-5.21/part02
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 2 (of 3)."
- # Contents: arc.1 arc.c arcadd.c arclzw.c arcmisc.c arcsq.c marc.c
- # Wrapped by vixie@cognition.pa.dec.com on Sat Apr 11 13:54:35 1992
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'arc.1' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'arc.1'\"
- else
- echo shar: Extracting \"'arc.1'\" \(7206 characters\)
- sed "s/^X//" >'arc.1' <<'END_OF_FILE'
- X.TH ARC 1L "11 Nov 1991" "Howard Chu@JPL" "LOCAL COMMANDS"
- X.SH NAME
- arc \- pc archive utility
- X.SH SYNOPSIS
- X.B arc
- a|m|u|f|d|x|e|r|p|l|v|t|c [ biswnoq ] [ g\fIpassword\fR ]
- X.I archive
- X[ \fIfilename\fR ...]
- X.SH DESCRIPTION
- X.I Arc
- is a general archive and file compression utility, used to maintain
- a compressed archive of files.
- An
- X.I archive
- is a single file that combines many files, reducing storage space
- and allowing multiple files to be handled as one.
- X.I Arc
- uses one of several compression methods for each file within the
- X.IR archive ,
- based on whichever method yields the smallest result.
- X.SH INSTRUCTIONS
- XExecute
- X.I arc
- with no arguments for fairly verbose, usable instructions.
- X.SH COMMAND SWITCHES
- X.TP 3
- a
- add files to archive. Copies the indicated files to the archive.
- X.TP
- m
- move files to archive. Same as 'a' switch except
- that the files are deleted from the directory as
- they are moved to the archive.
- X.TP
- u
- update files in archive. This switch will replace archived
- files when the named file is newer than the archived copy.
- New files will be added automatically.
- X.TP
- f
- freshen files in archive. Same as 'u' except that
- new files will not be added.
- X.TP
- d
- delete files in archive. The named files are removed from the archive.
- X.TP
- x,e
- extract files from archive. The named files are extracted
- from the archive and created in the current directory
- in an uncompressed state.
- X.TP
- r
- run one file with arguments from archive. Any
- program may be executed directly from the archive.
- The parameters given after the program name are passed to
- the program without modification.
- X.TP
- p
- copy files from archive to standard output. Useful
- with I/O redirection. A form-feed is appended after each file,
- to ease use with printers.
- X.TP
- l
- list files in archive. Limited information listing
- of files contained in an archive. Displays the
- filename, original length, and date last modified.
- If the 'n' option (see below) is used, only the
- filename is displayed.
- X.TP
- v
- verbose listing of files in archive. Complete
- information listing of files contained in an archive.
- Displays the filename, original length, storage method,
- storage factor (% savings), compressed size, date, time,
- and CRC.
- X.TP
- t
- test archive integrity. Computes CRC values for each member of
- the archive and compares against the previously saved value.
- X.TP
- c
- convert entry to new packing method. Convert files
- stored with older methods to newer methods that are
- more efficient. Also useful for files previously
- archived with the 's' option.
- X.SH OPTIONS
- X.TP 3
- b
- retain backup copy of archive. Keep the original
- archive file and rename to .BAK.
- This switch may be used with the
- following commands: a, m, u, f, d, c.
- X.TP
- i
- suppress image mode. This switch causes files to
- be treated as text files, and will translate their
- end-of-line sequence. (Unix's '\\n' vs. '\\r\\n' used
- on many other systems.) The default is to perform
- no translation when compressing or extracting files.
- This option makes dealing with text files much nicer,
- though the 'tr' command can also be used. ('\\r' in
- makefiles and C source code is such a nuisance...)
- X.TP
- s
- suppress compression. This forces new files to be
- saved using Method 2 (no compression). This switch
- may be used with the following commands: a, m, u, f, c.
- X.TP
- w
- suppress warning messages. This switch will keep
- warning messages from being displayed which is the default.
- Most warnings concern the deletion or existence of
- files with the same name.
- X.TP
- n
- suppress notes and comments. This switch will keep
- useful notes from being displayed which is the default.
- Most notes indicate what stage of compression is
- being run (analyze, compaction, storage).
- X.TP
- o
- overwrite existing files when extracting. This switch
- will make existing files silently get overwritten, instead
- of asking for confirmation, which is the default.
- X.TP
- q
- force Squash compression method. This switch causes
- the Squash compression method to be used, instead of
- Crunch, which is the default.
- X.TP
- g
- encrypt/decrypt archive entry. This is used to encode
- files so that others may not read them. BE CAREFUL!
- This must be the last parameter in the switches because
- everything following is part of the password.
- X.SH PROGRAMMING NOTES
- X.I Arc
- Version 2 differs from version 1 in that archive entries
- are automatically compressed when they are added to the archive,
- making a separate compression step unecessary. The nature of the
- compression is indicated by the header version number placed in
- each archive entry, as follows:
- X.nf
- X 1 = Old style, no compression
- X 2 = New style, no compression
- X 3 = Compression of repeated characters only
- X 4 = Compression of repeated characters plus Huffman SQueezing
- X 5 = Lempel-Zev packing of repeated strings (old style)
- X 6 = Lempel-Zev packing of repeated strings (new style)
- X 7 = Lempel-Zev Williams packing with improved hash function
- X 8 = Dynamic Lempel-Zev packing with adaptive reset
- X 9 = Squashing
- X.fi
- X
- Type 5, Lempel-Zev packing, was added as of version 4.0
- X
- Type 6 is Lempel-Zev packing where runs of repeated characters
- have been collapsed, and was added as of version 4.1
- X
- Type 7 is a variation of Lempel-Zev using a different hash
- function which yields speed improvements of 20-25%, and was
- added as of version 4.6
- X
- Type 8 is a different implementation of Lempel-Zev, using a
- variable code size and an adaptive block reset, and was added
- as of version 5.0
- X
- Type 9 is another variation of Lempel-Zev, using a larger
- hash table. This method was developed by Phil Katz, and is
- not supported by the "official" \fBARC\fP programs.
- X
- X.I Arc
- will look for environment variables named \fIARCTEMP\fP or
- X\fITMPDIR\fP, which, if present, indicates the pathname
- where temporary files should be created. This is typically
- the location of a RAMdisk on a microcomputer, "/tmp/" or
- left unset.
- X
- See the included documentation file for more details.
- X.SH HISTORY
- X\fIArc\fP has been in use in the CP/M and MSDOS world for many years.
- Thom Henderson developed the original version, but it is important to note that
- X\fIarc\fP is based on the file compression theories developed by Huffman, Welch,
- Knott, Knuth, and many other scientists. This implementation is based on
- version 5.21 of the MSDOS program.
- X.SH BUGS
- X\fIArc\fP behaves just like the PC version of the program; all functions
- of the "usage" display are working.
- XFull compatibility with PC ARC files is maintained, the price for which is
- that \fIarc\fP doesn't like long filenames, and can only archive files with
- names of up to 12 characters.
- It will *sometimes* do The Right Thing with them, but I suggest
- you put long-winded filenames in a "shar" before
- X.IR arc ing
- them.
- X
- There shouldn't be any problems, (hah!) but if you find any, please
- send them to me at:
- X
- X hyc@hanauma.jpl.nasa.gov
- X
- X.SH AUTHORS
- Original MSDOS program by Thom Henderson
- X.br
- COPYRIGHT(C) 1985-87 by System Enhancement Associates; ALL RIGHTS RESERVED
- X
- Original Lempel-Zev code derived from compress 4.0.
- Modified to support Squashing by Dan Lanciani (ddl@harvard.edu)
- Ported from MSDOS by Howard Chu,
- with help from John Gilmore (hoptoad!gnu), James Turner (daisy!turner)
- and others.
- END_OF_FILE
- if test 7206 -ne `wc -c <'arc.1'`; then
- echo shar: \"'arc.1'\" unpacked with wrong size!
- fi
- # end of 'arc.1'
- fi
- if test -f 'arc.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'arc.c'\"
- else
- echo shar: Extracting \"'arc.c'\" \(11929 characters\)
- sed "s/^X//" >'arc.c' <<'END_OF_FILE'
- X/*
- X * $Header: /var/local/hyc/src/arc/RCS/arc.c,v 2.0 1991/11/12 00:30:01 hyc Exp $
- X */
- X
- X/* ARC - Archive utility
- X
- X Version 5.21, created on 04/22/87 at 15:05:21
- X
- X(C) COPYRIGHT 1985-87 by System Enhancement Associates; ALL RIGHTS RESERVED
- X
- X By: Thom Henderson
- X
- X Description:
- X This program is a general archive utility, and is used to maintain
- X an archive of files. An "archive" is a single file that combines
- X many files, reducing storage space and allowing multiple files to
- X be handled as one.
- X
- X Instructions:
- X Run this program with no arguments for complete instructions.
- X
- X Programming notes:
- X ARC Version 2 differs from version 1 in that archive entries
- X are automatically compressed when they are added to the archive,
- X making a separate compression step unecessary. The nature of the
- X compression is indicated by the header version number placed in
- X each archive entry, as follows:
- X
- X 1 = Old style, no compression
- X 2 = New style, no compression
- X 3 = Compression of repeated characters only
- X 4 = Compression of repeated characters plus Huffman SQueezing
- X 5 = Lempel-Zev packing of repeated strings (old style)
- X 6 = Lempel-Zev packing of repeated strings (new style)
- X 7 = Lempel-Zev Williams packing with improved hash function
- X 8 = Dynamic Lempel-Zev packing with adaptive reset
- X 9 = Dynamic Lempel-Zev packing, larger hash table
- X
- X Type 5, Lempel-Zev packing, was added as of version 4.0
- X
- X Type 6 is Lempel-Zev packing where runs of repeated characters
- X have been collapsed, and was added as of version 4.1
- X
- X Type 7 is a variation of Lempel-Zev using a different hash
- X function which yields speed improvements of 20-25%, and was
- X added as of version 4.6
- X
- X Type 8 is a different implementation of Lempel-Zev, using a
- X variable code size and an adaptive block reset, and was added
- X as of version 5.0
- X
- X Type 9 is a slight modification of type 8, first used by Phil
- X Katz in his PKARC utilites. The primary difference is the use
- X of a hash table twice as large as for type 8, and that this
- X algorithm called Squashing, doesn't perform run-length encoding
- X on the input data.
- X
- X Verion 4.3 introduced a temporary file for holding the result
- X of the first crunch pass, thus speeding up crunching.
- X
- X Version 4.4 introduced the ARCTEMP environment string, so that
- X the temporary crunch file may be placed on a ramdisk. Also
- X added was the distinction bewteen Adding a file in all cases,
- X and Updating a file only if the disk file is newer than the
- X corresponding archive entry.
- X
- X The compression method to use is determined when the file is
- X added, based on whichever method yields the smallest result.
- X
- X Language:
- X Computer Innovations Optimizing C86
- X*/
- X#include <stdio.h>
- X#include "arc.h"
- X
- X#if UNIX
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#endif
- X
- X#include <string.h>
- X#if BSD
- X#include <strings.h>
- X#endif
- X
- X#if !__STDC__
- char *calloc(), *malloc(), *realloc();
- X#endif
- X
- VOID addarc(), delarc(), extarc(), lstarc(), tstarc(), cvtarc(), runarc();
- VOID arcdie();
- static VOID expandlst();
- X#if _MTS
- VOID etoa();
- X#endif
- X#if GEMDOS
- long _stksize = 30720;
- X#endif
- char *makefnam(); /* filename fixup routine */
- X
- static char **lst; /* files list */
- static int lnum; /* length of files list */
- X
- main(num, arg) /* system entry point */
- X int num; /* number of arguments */
- X char *arg[]; /* pointers to arguments */
- X{
- X char opt = 0;/* selected action */
- X char *a; /* option pointer */
- X VOID upper();/* case conversion routine */
- X char *envfind(); /* environment searcher */
- X int n; /* index */
- X char *arctemp2, *mktemp();
- X#if GEMDOS
- X VOID exitpause();
- X int append;
- X#endif
- X#if _MTS
- X fortran VOID guinfo();
- X char gotinf[4];
- X#endif
- X#if UNIX
- X struct stat sbuf;
- X#endif
- X
- X if (num < 3) {
- X printf("ARC - Archive utility, Version 5.21e, created on 10/30/91 at 14:30:21\n");
- X/* printf("(C) COPYRIGHT 1985,86,87 by System Enhancement Associates;");
- X printf(" ALL RIGHTS RESERVED\n\n");
- X printf("Please refer all inquiries to:\n\n");
- X printf(" System Enhancement Associates\n");
- X printf(" 21 New Street, Wayne NJ 07470\n\n");
- X printf("You may copy and distribute this program freely,");
- X printf(" provided that:\n");
- X printf(" 1) No fee is charged for such copying and");
- X printf(" distribution, and\n");
- X printf(" 2) It is distributed ONLY in its original,");
- X printf(" unmodified state.\n\n");
- X printf("If you like this program, and find it of use, then your");
- X printf(" contribution will\n");
- X printf("be appreciated. You may not use this product in a");
- X printf(" commercial environment\n");
- X printf("or a governmental organization without paying a license");
- X printf(" fee of $35. Site\n");
- X printf("licenses and commercial distribution licenses are");
- X printf(" available. A program\n");
- X printf("disk and printed documentation are available for $50.\n");
- X printf("\nIf you fail to abide by the terms of this license, ");
- X printf(" then your conscience\n");
- X printf("will haunt you for the rest of your life.\n\n"); */
- X#if MSDOS
- X printf("Usage: ARC {amufdxerplvtc}[bswnoq][g<password>]");
- X#endif
- X#if GEMDOS
- X printf("Usage: ARC {amufdxerplvtc}[bhswnoq][g<password>]");
- X#endif
- X#if UNIX
- X printf("Usage: arc {amufdxerplvtc}[biswnoq][g<password>]");
- X#endif
- X#if _MTS
- X printf("Parameters: {amufdxeplvtc}[biswnoq][g<password>]");
- X#endif
- X printf(" <archive> [<filename> . . .]\n");
- X printf("Where: a = add files to archive\n");
- X printf(" m = move files to archive\n");
- X printf(" u = update files in archive\n");
- X printf(" f = freshen files in archive\n");
- X printf(" d = delete files from archive\n");
- X printf(" x,e = extract files from archive\n");
- X#if !_MTS
- X printf(" r = run files from archive\n");
- X#endif
- X printf(" p = copy files from archive to");
- X printf(" standard output\n");
- X printf(" l = list files in archive\n");
- X printf(" v = verbose listing of files in archive\n");
- X printf(" t = test archive integrity\n");
- X printf(" c = convert entry to new packing method\n");
- X printf(" b = retain backup copy of archive\n");
- X#if GEMDOS
- X printf(" h = hold screen after finishing\n");
- X#endif
- X#if _MTS
- X printf(" i = suppress ASCII/EBCDIC translation\n");
- X#endif
- X#if UNIX
- X printf(" i = suppress image mode (translate EOL)\n");
- X#endif
- X printf(" s = suppress compression (store only)\n");
- X printf(" w = suppress warning messages\n");
- X printf(" n = suppress notes and comments\n");
- X printf(" o = overwrite existing files when");
- X printf(" extracting\n");
- X printf(" q = squash instead of crunching\n");
- X printf(" g = Encrypt/decrypt archive entry\n");
- X printf("\nAdapted from MSDOS by Howard Chu\n");
- X /*
- X * printf("\nPlease refer to the program documentation for");
- X * printf(" complete instructions.\n");
- X */
- X#if GEMDOS
- X exitpause();
- X#endif
- X return 1;
- X }
- X /* see where temp files go */
- X#if !_MTS
- X arctemp = calloc(1, STRLEN);
- X if (!(arctemp2 = envfind("ARCTEMP")))
- X arctemp2 = envfind("TMPDIR");
- X if (arctemp2) {
- X strcpy(arctemp, arctemp2);
- X n = strlen(arctemp);
- X if (arctemp[n - 1] != CUTOFF)
- X arctemp[n] = CUTOFF;
- X }
- X#if UNIX
- X else strcpy(arctemp, "/tmp/");
- X#endif
- X#if !MSDOS
- X {
- X static char tempname[] = "AXXXXXX";
- X strcat(arctemp, mktemp(tempname));
- X }
- X#else
- X strcat(arctemp, "$ARCTEMP");
- X#endif
- X#else
- X guinfo("SHFSEP ", gotinf);
- X sepchr[0] = gotinf[0];
- X guinfo("SCRFCHAR", gotinf);
- X tmpchr[0] = gotinf[0];
- X arctemp = "-$$$";
- X arctemp[0] = tmpchr[0];
- X#endif
- X arctemp2 = NULL;
- X
- X#if !UNIX
- X /* avoid any case problems with arguments */
- X
- X for (n = 1; n < num; n++) /* for each argument */
- X upper(arg[n]); /* convert it to uppercase */
- X#else
- X /* avoid case problems with command options */
- X upper(arg[1]); /* convert to uppercase */
- X#endif
- X
- X /* create archive names, supplying defaults */
- X#if UNIX
- X if (!stat(arg[2],&sbuf)) {
- X if ((sbuf.st_mode & S_IFMT) == S_IFDIR)
- X makefnam(arg[2],".arc",arcname);
- X else
- X strcpy(arcname,arg[2]);
- X } else
- X makefnam(arg[2],".arc",arcname);
- X#else
- X makefnam(arg[2], ".ARC", arcname);
- X#endif
- X /* makefnam(".$$$",arcname,newname); */
- X sprintf(newname, "%s.arc", arctemp);
- X makefnam(".BAK", arcname, bakname);
- X
- X /* now scan the command and see what we are to do */
- X
- X for (a = arg[1]; *a; a++) { /* scan the option flags */
- X#if !_MTS
- X if (index("AMUFDXEPLVTCR", *a)) { /* if a known command */
- X#else
- X if (index("AMUFDXEPLVTC", *a)) {
- X#endif
- X if (opt)/* do we have one yet? */
- X arcdie("Cannot mix %c and %c", opt, *a);
- X opt = *a; /* else remember it */
- X } else if (*a == 'B') /* retain backup copy */
- X keepbak = 1;
- X
- X else if (*a == 'W') /* suppress warnings */
- X warn = 0;
- X#if !DOS
- X else if (*a == 'I') /* image mode, no ASCII/EBCDIC x-late */
- X image = !image;
- X#endif
- X#if GEMDOS
- X else if (*a == 'H') /* pause before exit */
- X hold = 1;
- X#endif
- X
- X else if (*a == 'N') /* suppress notes and comments */
- X note = 0;
- X
- X else if (*a == 'O') /* overwrite file on extract */
- X overlay = 1;
- X
- X else if (*a == 'G') { /* garble */
- X password = a + 1;
- X while (*a)
- X a++;
- X a--;
- X#if _MTS
- X etoa(password, strlen(password));
- X#endif
- X } else if (*a == 'S') /* storage kludge */
- X nocomp = 1;
- X
- X else if (*a == 'K') /* special kludge */
- X kludge = 1;
- X
- X else if (*a == 'Q') /* use squashing */
- X dosquash = 1;
- X
- X else if (*a == '-' || *a == '/') /* UNIX and PC-DOS
- X * option markers */
- X ;
- X
- X else
- X arcdie("%c is an unknown command", *a);
- X }
- X
- X if (!opt)
- X arcdie("I have nothing to do!");
- X
- X /* get the files list set up */
- X
- X lnum = num - 3; /* initial length of list */
- X lst = (char **) calloc((lnum==0) ? 1:lnum,
- X sizeof(char *)); /* initial list */
- X for (n = 3; n < num; n++)
- X lst[n - 3] = arg[n];
- X
- X for (n = 0; n < lnum;) {/* expand indirect references */
- X if (*lst[n] == '@')
- X expandlst(n);
- X#if GEMDOS /* redirect stdout from the desktop...*/
- X else if (*lst[n] == '>') {
- X arctemp2 = (++lst[n]);
- X lst[n] = lst[--lnum]; /* delete this entry */
- X if (arctemp2[0] == '>') {
- X append = 1;
- X arctemp2++;
- X }
- X else append = 0;
- X }
- X#endif
- X else
- X n++;
- X }
- X#if GEMDOS
- X if (arctemp2)
- X freopen(arctemp2,append ? "a" : "w",stdout);
- X#endif
- X
- X /* act on whatever action command was given */
- X
- X switch (opt) { /* action depends on command */
- X case 'A': /* Add */
- X case 'M': /* Move */
- X case 'U': /* Update */
- X case 'F': /* Freshen */
- X addarc(lnum, lst, (opt == 'M'), (opt == 'U'), (opt == 'F'));
- X break;
- X
- X case 'D': /* Delete */
- X delarc(lnum, lst);
- X break;
- X
- X case 'E': /* Extract */
- X case 'X': /* eXtract */
- X case 'P': /* Print */
- X extarc(lnum, lst, (opt == 'P'));
- X break;
- X
- X case 'V': /* Verbose list */
- X bose = 1;
- X case 'L': /* List */
- X lstarc(lnum, lst);
- X break;
- X
- X case 'T': /* Test */
- X tstarc();
- X break;
- X
- X case 'C': /* Convert */
- X cvtarc(lnum, lst);
- X break;
- X#if !_MTS
- X case 'R': /* Run */
- X runarc(lnum, lst);
- X break;
- X#endif
- X default:
- X arcdie("I don't know how to do %c yet!", opt);
- X }
- X#if GEMDOS
- X if (hold)
- X exitpause();
- X#endif
- X return nerrs;
- X}
- static VOID
- expandlst(n) /* expand an indirect reference */
- X int n; /* number of entry to expand */
- X{
- X FILE *lf, *fopen(); /* list file, opener */
- X char buf[100]; /* input buffer */
- X int x; /* index */
- X char *p = lst[n] + 1; /* filename pointer */
- X
- X if (*p) { /* use name if one was given */
- X makefnam(p, ".CMD", buf);
- X if (!(lf = fopen(buf, "r")))
- X arcdie("Cannot read list of files in %s", buf);
- X } else
- X lf = stdin; /* else use standard input */
- X
- X for (x = n + 1; x < lnum; x++) /* drop reference from the list */
- X lst[x - 1] = lst[x];
- X lnum--;
- X
- X while (fscanf(lf, "%99s", buf) > 0) { /* read in the list */
- X if (!(lst =(char **)realloc(lst, (lnum + 1) * sizeof(char *))))
- X arcdie("too many file references");
- X
- X lst[lnum] = malloc(strlen(buf) + 1);
- X strcpy(lst[lnum], buf); /* save the name */
- X lnum++;
- X }
- X
- X if (lf != stdin) /* avoid closing standard input */
- X fclose(lf);
- X}
- END_OF_FILE
- if test 11929 -ne `wc -c <'arc.c'`; then
- echo shar: \"'arc.c'\" unpacked with wrong size!
- fi
- # end of 'arc.c'
- fi
- if test -f 'arcadd.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'arcadd.c'\"
- else
- echo shar: Extracting \"'arcadd.c'\" \(10176 characters\)
- sed "s/^X//" >'arcadd.c' <<'END_OF_FILE'
- X/*
- X * $Header: /var/local/hyc/src/arc/RCS/arcadd.c,v 2.0 1991/11/12 02:31:25 hyc Exp $
- X */
- X
- X/*
- X * ARC - Archive utility - ARCADD
- X *
- X * Version 3.40, created on 06/18/86 at 13:10:18
- X *
- X * (C) COPYRIGHT 1985,86 by System Enhancement Associates; ALL RIGHTS RESERVED
- X *
- X * By: Thom Henderson
- X *
- X * Description: This file contains the routines used to add files to an archive.
- X *
- X * Language: Computer Innovations Optimizing C86
- X */
- X#include <stdio.h>
- X#include "arc.h"
- X#if _MTS
- X#include <mts.h>
- X#include <ctype.h>
- X#endif
- X#include <string.h>
- X#if BSD
- X#include <strings.h>
- X#endif
- X
- static int addfile();
- int readhdr(), unlink();
- X#if UNIX
- int izadir();
- X#endif
- VOID writehdr(), filecopy(), getstamp();
- VOID pack(), closearc(), openarc(), arcdie();
- X
- X#ifndef __STDC__
- char *malloc(), *realloc(); /* memory allocators */
- X#ifndef _AIX
- VOID free();
- X#endif
- X#endif
- X
- VOID
- addarc(num, arg, move, update, fresh) /* add files to archive */
- X int num; /* number of arguments */
- X char *arg[]; /* pointers to arguments */
- int move; /* true if moving file */
- int update; /* true if updating */
- int fresh; /* true if freshening */
- X{
- X char *d, *dir(); /* directory junk */
- X char buf[STRLEN]; /* pathname buffer */
- X char **path; /* pointer to pointers to paths */
- X char **name; /* pointer to pointers to names */
- X int nfiles = 0; /* number of files in lists */
- X int notemp; /* true until a template works */
- X int nowork = 1; /* true until files are added */
- X char *i; /* string indexing junk */
- X int n; /* index */
- X#if MSDOS
- X unsigned int coreleft(); /* remaining memory reporter */
- X#endif
- X int addbunch();
- X
- X if (num < 1) { /* if no files named */
- X num = 1; /* then fake one */
- X#if DOS
- X arg[0] = "*.*"; /* add everything */
- X#endif
- X#if UNIX
- X arg[0] = "*";
- X#endif
- X#if _MTS
- X arg[0] = "?";
- X#endif
- X }
- X path = (char **) malloc(sizeof(char **));
- X name = (char **) malloc(sizeof(char **));
- X
- X
- X for (n = 0; n < num; n++) { /* for each template supplied */
- X strcpy(buf, arg[n]); /* get ready to fix path */
- X#if !_MTS
- X if (!(i = rindex(buf, '\\')))
- X if (!(i = rindex(buf, '/')))
- X if (!(i = rindex(buf, ':')))
- X i = buf - 1;
- X#else
- X if (!(i = rindex(buf, sepchr[0])))
- X if (buf[0] != tmpchr[0])
- X i = buf - 1;
- X else
- X i = buf;
- X#endif
- X i++; /* pointer to where name goes */
- X
- X notemp = 1; /* reset files flag */
- X for (d = dir(arg[n]); d; d = dir(NULL)) {
- X notemp = 0; /* template is giving results */
- X nfiles++; /* add each matching file */
- X path = (char **) realloc(path, nfiles * sizeof(char **));
- X name = (char **) realloc(name, nfiles * sizeof(char **));
- X strcpy(i, d); /* put name in path */
- X path[nfiles - 1] = malloc(strlen(buf) + 1);
- X strcpy(path[nfiles - 1], buf);
- X name[nfiles - 1] = d; /* save name */
- X#if MSDOS
- X if (coreleft() < 5120) {
- X nfiles = addbunch(nfiles, path, name, move, update, fresh);
- X nowork = nowork && !nfiles;
- X while (nfiles) {
- X free(path[--nfiles]);
- X free(name[nfiles]);
- X }
- X free(path);
- X free(name);
- X path = name = NULL;
- X }
- X#endif
- X }
- X if (notemp && warn)
- X printf("No files match: %s\n", arg[n]);
- X }
- X
- X if (nfiles) {
- X nfiles = addbunch(nfiles, path, name, move, update, fresh);
- X nowork = nowork && !nfiles;
- X while (nfiles) {
- X free(path[--nfiles]);
- X free(name[nfiles]);
- X }
- X free(path);
- X free(name);
- X }
- X if (nowork && warn)
- X printf("No files were added.\n");
- X}
- X
- int
- addbunch(nfiles, path, name, move, update, fresh) /* add a bunch of files */
- X int nfiles; /* number of files to add */
- X char **path; /* pointers to pathnames */
- X char **name; /* pointers to filenames */
- X int move; /* true if moving file */
- X int update; /* true if updating */
- X int fresh; /* true if freshening */
- X{
- X int m, n; /* indices */
- X char *d; /* swap pointer */
- X struct heads hdr; /* file header data storage */
- X
- X for (n = 0; n < nfiles - 1; n++) { /* sort the list of names */
- X for (m = n + 1; m < nfiles; m++) {
- X if (strcmp(name[n], name[m]) > 0) {
- X d = path[n];
- X path[n] = path[m];
- X path[m] = d;
- X d = name[n];
- X name[n] = name[m];
- X name[m] = d;
- X }
- X }
- X }
- X
- X for (n = 0; n < nfiles - 1;) { /* consolidate the list of names */
- X if (!strcmp(path[n], path[n + 1]) /* if duplicate names */
- X ||!strcmp(path[n], arcname) /* or this archive */
- X#if UNIX
- X ||izadir(path[n]) /* or a directory */
- X#endif
- X ||!strcmp(path[n], newname) /* or the new version */
- X ||!strcmp(path[n], bakname)) { /* or its backup */
- X free(path[n]); /* then forget the file */
- X free(name[n]);
- X for (m = n; m < nfiles - 1; m++) {
- X path[m] = path[m + 1];
- X name[m] = name[m + 1];
- X }
- X nfiles--;
- X } else
- X n++; /* else test the next one */
- X }
- X
- X if (!strcmp(path[n], arcname) /* special check for last file */
- X ||!strcmp(path[n], newname) /* courtesy of Rick Moore */
- X#if UNIX
- X ||izadir(path[n])
- X#endif
- X || !strcmp(path[n], bakname)) {
- X free(path[n]);
- X free(name[n]);
- X nfiles--;
- X }
- X if (!nfiles) /* make sure we got some */
- X return 0;
- X
- X for (n = 0; n < nfiles - 1; n++) { /* watch out for duplicate
- X * names */
- X if (!strcmp(name[n], name[n + 1]))
- X arcdie("Duplicate filenames:\n %s\n %s", path[n], path[n + 1]);
- X }
- X openarc(1); /* open archive for changes */
- X
- X for (n = 0; n < nfiles;) { /* add each file in the list */
- X if (addfile(path[n], name[n], update, fresh) < 0) {
- X free(path[n]); /* remove this name if */
- X free(name[n]); /* it wasn't added */
- X for (m = n; m < nfiles-1 ; m++) {
- X path[m] = path[m+1];
- X name[m] = name[m+1];
- X }
- X nfiles--;
- X } else n++;
- X }
- X
- X /* now we must copy over all files that follow our additions */
- X
- X while (readhdr(&hdr, arc)) { /* while more entries to copy */
- X writehdr(&hdr, new);
- X filecopy(arc, new, hdr.size);
- X }
- X hdrver = 0; /* archive EOF type */
- X writehdr(&hdr, new); /* write out our end marker */
- X closearc(1); /* close archive after changes */
- X
- X if (move) { /* if this was a move */
- X for (n = 0; n < nfiles; n++) { /* then delete each file
- X * added */
- X if (unlink(path[n]) && warn) {
- X printf("Cannot unsave %s\n", path[n]);
- X nerrs++;
- X }
- X }
- X }
- X return nfiles; /* say how many were added */
- X}
- X
- static int
- addfile(path, name, update, fresh) /* add named file to archive */
- X char *path; /* path name of file to add */
- X char *name; /* name of file to add */
- X int update; /* true if updating */
- X int fresh; /* true if freshening */
- X{
- X struct heads nhdr; /* data regarding the new file */
- X struct heads ohdr; /* data regarding an old file */
- X FILE *f, *fopen(); /* file to add, opener */
- X long starts, ftell(); /* file locations */
- X int upd = 0;/* true if replacing an entry */
- X
- X#if !_MTS
- X if (!(f = fopen(path, OPEN_R)))
- X#else
- X if (image)
- X f = fopen(path, OPEN_R);
- X else
- X f = fopen(path, "r");
- X if (!f)
- X#endif
- X {
- X if (warn) {
- X printf("Cannot read file: %s\n", path);
- X nerrs++;
- X }
- X return(-1);
- X }
- X#if !DOS
- X if (strlen(name) >= FNLEN) {
- X if (warn) {
- X char buf[STRLEN];
- X printf("WARNING: File %s name too long!\n", name);
- X name[FNLEN-1]='\0';
- X while(1) {
- X printf(" Truncate to %s (y/n)? ", name);
- X fflush(stdout);
- X fgets(buf, STRLEN, stdin);
- X *buf = toupper(*buf);
- X if (*buf == 'Y' || *buf == 'N')
- X break;
- X }
- X if (*buf == 'N') {
- X printf("Skipping...\n");
- X fclose(f);
- X return(-1);
- X }
- X }
- X else {
- X if (note)
- X printf("Skipping file: %s - name too long.\n",
- X name);
- X fclose(f);
- X return(-1);
- X }
- X }
- X#endif
- X strcpy(nhdr.name, name);/* save name */
- X nhdr.size = 0; /* clear out size storage */
- X nhdr.crc = 0; /* clear out CRC check storage */
- X#if !_MTS
- X getstamp(f, &nhdr.date, &nhdr.time);
- X#else
- X {
- X int inlen;
- X struct GDDSECT *region;
- X
- X region=gdinfo(f->_fd._fdub);
- X inlen=region->GDINLEN;
- X buf=malloc(inlen); /* maximum line length */
- X setbuffer(f,buf,inlen);
- X f->_mods|=_NOIC; /* Don't do "$continue with" */
- X f->_mods&=~_IC; /* turn it off, if set... */
- X }
- X getstamp(path, &nhdr.date, &nhdr.time);
- X#endif
- X
- X /* position archive to spot for new file */
- X
- X if (arc) { /* if adding to existing archive */
- X starts = ftell(arc); /* where are we? */
- X while (readhdr(&ohdr, arc)) { /* while more files to check */
- X if (!strcmp(ohdr.name, nhdr.name)) {
- X upd = 1; /* replace existing entry */
- X if (update || fresh) { /* if updating or
- X * freshening */
- X if (nhdr.date < ohdr.date
- X || (nhdr.date == ohdr.date && nhdr.time <= ohdr.time)) {
- X fseek(arc, starts, 0);
- X fclose(f);
- X return(0);/* skip if !newer */
- X }
- X }
- X }
- X if (strcmp(ohdr.name, nhdr.name) >= 0)
- X break; /* found our spot */
- X
- X writehdr(&ohdr, new); /* entry preceeds update;
- X * keep it */
- X filecopy(arc, new, ohdr.size);
- X starts = ftell(arc); /* now where are we? */
- X }
- X
- X if (upd) { /* if an update */
- X if (note) {
- X printf("Updating file: %-12s ", name);
- X fflush(stdout);
- X }
- X fseek(arc, ohdr.size, 1);
- X } else if (fresh) { /* else if freshening */
- X fseek(arc, starts, 0); /* then do not add files */
- X fclose(f);
- X return(0);
- X } else { /* else adding a new file */
- X if (note) {
- X printf("Adding file: %-12s ", name);
- X fflush(stdout);
- X }
- X fseek(arc, starts, 0); /* reset for next time */
- X }
- X } else { /* no existing archive */
- X if (fresh) { /* cannot freshen nothing */
- X fclose(f);
- X return(0);
- X } else if (note) { /* else adding a file */
- X printf("Adding file: %-12s ", name);
- X fflush(stdout);
- X }
- X }
- X
- X starts = ftell(new); /* note where header goes */
- X hdrver = ARCVER; /* anything but end marker */
- X writehdr(&nhdr, new); /* write out header skeleton */
- X#if _MTS
- X atoe(nhdr.name, FNLEN); /* writehdr translated this... */
- X#endif
- X pack(f, new, &nhdr); /* pack file into archive */
- X fseek(new, starts, 0); /* move back to header skeleton */
- X writehdr(&nhdr, new); /* write out real header */
- X fseek(new, nhdr.size, 1); /* skip over data to next header */
- X fclose(f); /* all done with the file */
- X return(0);
- X}
- END_OF_FILE
- if test 10176 -ne `wc -c <'arcadd.c'`; then
- echo shar: \"'arcadd.c'\" unpacked with wrong size!
- fi
- # end of 'arcadd.c'
- fi
- if test -f 'arclzw.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'arclzw.c'\"
- else
- echo shar: Extracting \"'arclzw.c'\" \(22078 characters\)
- sed "s/^X//" >'arclzw.c' <<'END_OF_FILE'
- X/*
- X * $Header: /var/local/hyc/src/arc/RCS/arclzw.c,v 2.0 1991/11/12 00:30:01 hyc Exp $
- X */
- X
- X/*
- X * ARC - Archive utility - ARCLZW
- X *
- X * Version 2.03, created on 10/24/86 at 11:46:22
- X *
- X * (C) COPYRIGHT 1985,86 by System Enhancement Associates; ALL RIGHTS RESERVED
- X *
- X * By: Thom Henderson
- X *
- X * Description: This file contains the routines used to implement Lempel-Zev
- X * data compression, which calls for building a coding table on the fly.
- X * This form of compression is especially good for encoding files which
- X * contain repeated strings, and can often give dramatic improvements over
- X * traditional Huffman SQueezing.
- X *
- X * Language: Computer Innovations Optimizing C86
- X *
- X * Programming notes: In this section I am drawing heavily on the COMPRESS
- X * program from UNIX. The basic method is taken from "A Technique for High
- X * Performance Data Compression", Terry A. Welch, IEEE Computer Vol 17, No 6
- X * (June 1984), pp 8-19. Also see "Knuth's Fundamental Algorithms", Donald
- X * Knuth, Vol 3, Section 6.4.
- X *
- X * As best as I can tell, this method works by tracing down a hash table of code
- X * strings where each entry has the property:
- X *
- X * if <string> <char> is in the table then <string> is in the table.
- X */
- X#include <stdio.h>
- X#include "arc.h"
- X
- VOID arcdie();
- X#if MSDOS
- char *setmem();
- X#else
- X#if NEEDMEMSET
- char *memset();
- X#else
- X#include <memory.h>
- X#endif
- X#endif
- X
- X#include "proto.h"
- static VOID putcode();
- X/* definitions for older style crunching */
- X
- X#define FALSE 0
- X#define TRUE !FALSE
- X#define TABSIZE 4096
- X#define NO_PRED 0xFFFF
- X#define EMPTY 0xFFFF
- X#define NOT_FND 0xFFFF
- X
- extern u_char pinbuf[MYBUF];
- u_char *inbeg, *inend;
- u_char outbuf[MYBUF];
- u_char *outbeg, *outend = &outbuf[MYBUF - 1];
- X
- static int sp; /* current stack pointer */
- static int inflag;
- X
- struct entry { /* string table entry format */
- X char used; /* true when this entry is in use */
- X u_char follower; /* char following string */
- X u_short next; /* ptr to next in collision list */
- X u_short predecessor; /* code for preceeding string */
- X}; /* string_tab[TABSIZE]; the code string
- X * table */
- X
- X
- X/* definitions for the new dynamic Lempel-Zev crunching */
- X
- X#define CRBITS 12 /* maximum bits per code */
- X#define CRHSIZE 5003 /* 80% occupancy */
- X#define CRGAP 2048 /* ratio check interval */
- X#define SQBITS 13 /* Squash values of above */
- X#define SQHSIZE 10007
- X#define SQGAP 10000
- X#define INIT_BITS 9 /* initial number of bits/code */
- X
- static int Bits;
- static int Hsize;
- static int Check_Gap;
- X
- static int n_bits; /* number of bits/code */
- static int maxcode; /* maximum code, given n_bits */
- X#define MAXCODE(n) ((1<<(n)) - 1) /* maximum code calculation */
- static int max_maxcode; /* 1 << BITS; largest possible code (+1) */
- X
- static char buf[SQBITS]; /* input/output buffer */
- X
- static u_char lmask[9] = /* left side masks */
- X{
- X 0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00
- X};
- static u_char rmask[9] = /* right side masks */
- X{
- X 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
- X};
- X
- static int offset; /* byte offset for code output */
- static long in_count; /* length of input */
- static int in_off; /* where to start reading input */
- static long bytes_out; /* length of compressed output */
- static long bytes_last; /* previous output size */
- static u_short ent;
- static long fcode;
- static int hshift;
- X
- X/*
- X * To save much memory (which we badly need at this point), we overlay the
- X * table used by the previous version of Lempel-Zev with those used by the
- X * new version. Since no two of these routines will be used together, we can
- X * safely do this.
- X */
- X
- long htab[SQHSIZE]; /* hash code table (crunch) */
- u_short codetab[SQHSIZE]; /* string code table (crunch) */
- static struct entry *string_tab = (struct entry *) htab; /* old crunch string
- X * table */
- X
- static u_short *prefix = codetab; /* prefix code table (uncrunch) */
- static u_char *suffix = (u_char *) htab; /* suffix table (uncrunch) */
- X
- static int free_ent; /* first unused entry */
- u_char *stack = (u_char *) & htab[1 << SQBITS];
- X /* local push/pop stack */
- X
- X/*
- X * block compression parameters -- after all codes are used up, and
- X * compression rate changes, start over.
- X */
- X
- static int clear_flg;
- static long ratio;
- static long checkpoint;
- VOID upd_tab();
- X
- X/*
- X * the next two codes should not be changed lightly, as they must not lie
- X * within the contiguous general code space.
- X */
- X#define FIRST 257 /* first free entry */
- X#define CLEAR 256 /* table clear output code */
- X
- X/*
- X * The cl_block() routine is called at each checkpoint to determine if
- X * compression would likely improve by resetting the code table.
- X */
- X
- static VOID
- cl_block(t) /* table clear for block compress */
- X FILE *t; /* our output file */
- X{
- X long rat;
- X
- X checkpoint = in_count + Check_Gap;
- X
- X if (in_count > 0x007fffffL) { /* shift will overflow */
- X rat = bytes_out >> 8;
- X if (rat == 0) /* Don't divide by zero */
- X rat = 0x7fffffffL;
- X else
- X rat = in_count / rat;
- X } else
- X rat = (in_count << 8) / bytes_out; /* 8 fractional bits */
- X
- X if (rat > ratio)
- X ratio = rat;
- X else {
- X ratio = 0;
- X setmem(htab, Hsize * sizeof(long), 0xff);
- X free_ent = FIRST;
- X clear_flg = 1;
- X putcode(CLEAR, t);
- X }
- X}
- X
- X#define FLUSH_BUF(bytes) \
- do { bytes_out += bytes;\
- X outbeg += bytes;\
- X if (outend - outbeg < Bits) {\
- X putb_pak(outbuf, (u_int) (bytes_out - bytes_last), t);\
- X bytes_last = bytes_out;\
- X outbeg = outbuf;\
- X }\
- X offset = 0;\
- X} while (0)
- X
- X/*****************************************************************
- X *
- X * Output a given code.
- X * Inputs:
- X * code: A n_bits-bit integer. If == -1, then EOF. This assumes
- X * that n_bits =< (LONG)wordsize - 1.
- X * Outputs:
- X * Outputs code to the file.
- X * Assumptions:
- X * Chars are 8 bits long.
- X * Algorithm:
- X * Maintain a BITS character long buffer (so that 8 codes will
- X * fit in it exactly). When the buffer fills up empty it and start over.
- X */
- X
- static VOID
- putcode(code, t) /* output a code */
- X int code; /* code to output */
- X FILE *t; /* where to put it */
- X{
- X int r_off = offset; /* right offset */
- X int bits = n_bits; /* bits to go */
- X u_char *bp = outbeg; /* buffer pointer */
- X
- X register int ztmp;
- X
- X bp += (r_off >> 3); /* Get to the first byte. */
- X r_off &= 7;
- X
- X /*
- X * Since code is always >= 8 bits, only need to mask the
- X * first hunk on the left.
- X */
- X ztmp = (code << r_off) & lmask[r_off];
- X *bp = (*bp & rmask[r_off]) | ztmp;
- X bp++;
- X bits -= (8 - r_off);
- X code >>= (8 - r_off);
- X
- X /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
- X if (bits >= 8) {
- X *bp++ = code;
- X code >>= 8;
- X bits -= 8;
- X }
- X /* Last bits. */
- X if (bits)
- X *bp = code;
- X offset += n_bits;
- X
- X if (offset == (n_bits << 3))
- X FLUSH_BUF(n_bits);
- X /*
- X * If the next entry is going to be too big for the code
- X * size, then increase it, if possible.
- X */
- X if (free_ent > maxcode || clear_flg > 0) {
- X /*
- X * Write the whole buffer, because the input side
- X * won't discover the size increase until after it
- X * has read it.
- X */
- X if (offset > 0)
- X FLUSH_BUF(n_bits);
- X
- X if (clear_flg) { /* reset if clearing */
- X maxcode = MAXCODE(n_bits = INIT_BITS);
- X clear_flg = 0;
- X } else {/* else use more bits */
- X n_bits++;
- X if (n_bits == Bits)
- X maxcode = max_maxcode;
- X else
- X maxcode = MAXCODE(n_bits);
- X }
- X }
- X}
- X
- X/*****************************************************************
- X *
- X * Read codes from the input file. If EOF, return -1.
- X * Inputs:
- X * cmpin
- X * Outputs:
- X * code or -1 is returned.
- X */
- X
- static int
- getcode(f) /* get a code */
- X FILE *f; /* file to get from */
- X{
- X int code;
- X static int size = 0;
- X int r_off, bits;
- X u_char *bp = (u_char *) buf;
- X
- X if (clear_flg > 0 || offset >= size || free_ent > maxcode) {
- X /*
- X * If the next entry will be too big for the current code
- X * size, then we must increase the size. This implies reading
- X * a new buffer full, too.
- X */
- X if (free_ent > maxcode) {
- X n_bits++;
- X if (n_bits == Bits)
- X maxcode = max_maxcode; /* won't get any bigger
- X * now */
- X else
- X maxcode = MAXCODE(n_bits);
- X }
- X if (clear_flg > 0) {
- X maxcode = MAXCODE(n_bits = INIT_BITS);
- X clear_flg = 0;
- X }
- X for (size = 0; size < n_bits; size++) {
- X if (inbeg >= inend) {
- X u_int inlen = getb_unp(f);
- X if (inlen == 0) {
- X code = EOF;
- X break;
- X } else {
- X inbeg = pinbuf;
- X inend = &inbeg[inlen];
- X }
- X }
- X code = *inbeg++;
- X buf[size] = (char) code;
- X }
- X if (size <= 0)
- X return -1; /* end of file */
- X
- X offset = 0;
- X /* Round size down to integral number of codes */
- X size = (size << 3) - (n_bits - 1);
- X }
- X r_off = offset;
- X bits = n_bits;
- X
- X /*
- X * Get to the first byte.
- X */
- X bp += (r_off >> 3);
- X r_off &= 7;
- X
- X /* Get first part (low order bits) */
- X code = (*bp++ >> r_off);
- X bits -= 8 - r_off;
- X r_off = 8 - r_off; /* now, offset into code word */
- X
- X /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
- X if (bits >= 8) {
- X code |= *bp++ << r_off;
- X r_off += 8;
- X bits -= 8;
- X }
- X /* high order bits. */
- X code |= (*bp & rmask[bits]) << r_off;
- X offset += n_bits;
- X
- X return code & MAXCODE(Bits);
- X}
- X
- X/*
- X * compress a file
- X *
- X * Algorithm: use open addressing double hashing (no chaining) on the prefix
- X * code / next character combination. We do a variant of Knuth's algorithm D
- X * (vol. 3, sec. 6.4) along with G. Knott's relatively-prime secondary probe.
- X * Here, the modular division first probe is gives way to a faster
- X * exclusive-or manipulation. Also do block compression with an adaptive
- X * reset, where the code table is cleared when the compression ratio
- X * decreases, but after the table fills. The variable-length output codes
- X * are re-sized at this point, and a special CLEAR code is generated for the
- X * decompressor.
- X */
- X
- VOID
- init_cm(buf) /* initialize for compression */
- X u_char *buf; /* input buffer */
- X{
- X offset = 0;
- X clear_flg = 0;
- X ratio = 0;
- X in_count = 1;
- X in_off = 1;
- X maxcode = MAXCODE(n_bits = INIT_BITS);
- X free_ent = FIRST;
- X n_bits = INIT_BITS; /* set starting code size */
- X outbeg = outbuf;
- X bytes_last = 0;
- X
- X if (dosquash) {
- X Bits = SQBITS;
- X Hsize = SQHSIZE;
- X Check_Gap = SQGAP;
- X bytes_out = 0;
- X } else {
- X Bits = CRBITS;
- X Hsize = CRHSIZE;
- X Check_Gap = CRGAP;
- X bytes_out = 1;
- X *outbeg++ = Bits; /* note our max code length */
- X }
- X checkpoint = Check_Gap;
- X max_maxcode = 1 << Bits;
- X setmem(htab, Hsize * sizeof(long), 0xff);
- X
- X ent = *buf;
- X hshift = 0;
- X for (fcode = (long) Hsize; fcode < 65536L; fcode *= 2L)
- X hshift++;
- X hshift = 8 - hshift;
- X}
- X
- VOID
- lzw_buf(buf, len, t) /* compress a character */
- X u_char *buf; /* buffer to compress */
- X u_int len; /* length of buffer */
- X FILE *t; /* where to put it */
- X{
- X int i, j;
- X int disp;
- X
- X j = in_off;
- X buf += in_off;
- X in_off = 0;
- X for (; j < len; j++, buf++) {
- X in_count++;
- X
- X fcode = (long) (((long) *buf << Bits) + ent);
- X i = (*buf << hshift) ^ ent; /* xor hashing */
- X
- X if (htab[i] == fcode) {
- X ent = codetab[i];
- X continue;
- X } else if (htab[i] < 0) /* empty slot */
- X goto nomatch;
- X disp = Hsize - i; /* secondary hash (after G.Knott) */
- X if (i == 0)
- X disp = 1;
- X
- probe:
- X if ((i -= disp) < 0)
- X i += Hsize;
- X
- X if (htab[i] == fcode) {
- X ent = codetab[i];
- X continue;
- X }
- X if (htab[i] > 0)
- X goto probe;
- X
- nomatch:
- X putcode(ent, t);
- X ent = *buf;
- X if (free_ent < max_maxcode) {
- X codetab[i] = free_ent++; /* code -> hashtable */
- X htab[i] = fcode;
- X } else if (in_count >= checkpoint)
- X cl_block(t); /* check for adaptive reset */
- X }
- X}
- X
- long
- pred_cm(t) /* report compressed size */
- X FILE *t; /* where to put it */
- X{
- X putcode(ent, t); /* put out the final code */
- X
- X offset = (offset + 7) / 8;
- X bytes_out += offset;
- X
- X return bytes_out; /* say how big it got */
- X}
- X
- VOID
- flsh_cm(t) /* flush compressed file */
- X FILE *t;
- X{
- X putb_pak(outbuf, (u_int) (bytes_out - bytes_last), t);
- X}
- X
- X/*
- X * Decompress a file. This routine adapts to the codes in the file building
- X * the string table on-the-fly; requiring no table to be stored in the
- X * compressed file. The tables used herein are shared with those of the
- X * compress() routine. See the definitions above.
- X */
- X
- VOID
- decomp(squash, f, t) /* decompress a file */
- X int squash; /* squashed or crunched? */
- X FILE *f; /* file to read codes from */
- X FILE *t; /* file to write text to */
- X{
- X u_char *stackp;
- X int finchar;
- X int code, oldcode, incode;
- X VOID (*output) PROTO((u_char *buf, u_int len, FILE *f));
- X u_int inlen;
- X
- X inlen = getb_unp(f);
- X inbeg = pinbuf;
- X inend = &inbeg[inlen];
- X outbeg = outbuf;
- X
- X if (squash) {
- X Bits = SQBITS;
- X output = putb_unp;
- X } else {
- X Bits = CRBITS;
- X output = putb_ncr;
- X if ((code = *inbeg++) != CRBITS)
- X arcdie("File packed with %d bits, I can only handle %d",
- X code, CRBITS);
- X }
- X
- X if (inlen<=0)
- X return;
- X
- X max_maxcode = 1 << Bits;
- X clear_flg = 0;
- X
- X n_bits = INIT_BITS; /* set starting code size */
- X
- X /*
- X * As above, initialize the first 256 entries in the table.
- X */
- X maxcode = MAXCODE(n_bits);
- X setmem(prefix, 256 * sizeof(short), 0); /* reset decode string table */
- X for (code = 255; code >= 0; code--)
- X suffix[code] = (u_char) code;
- X
- X free_ent = FIRST;
- X
- X finchar = oldcode = getcode(f);
- X if (oldcode == -1) /* EOF already? */
- X return; /* Get out of here */
- X *outbeg++ = finchar; /* first code must be 8 bits=char */
- X stackp = stack;
- X
- X while ((code = getcode(f)) > -1) {
- X if (code == CLEAR) { /* reset string table */
- X setmem(prefix, 256 * sizeof(short), 0);
- X clear_flg = 1;
- X free_ent = FIRST - 1;
- X if ((code = getcode(f)) == -1) /* O, untimely death! */
- X break;
- X }
- X incode = code;
- X /*
- X * Special case for KwKwK string.
- X */
- X if (code >= free_ent) {
- X if (code > free_ent) {
- X if (warn) {
- X printf("Corrupted compressed file.\n");
- X printf("Invalid code %d when max is %d.\n",
- X code, free_ent);
- X }
- X nerrs++;
- X break;
- X }
- X *stackp++ = finchar;
- X code = oldcode;
- X }
- X /*
- X * Generate output characters in reverse order
- X */
- X while (code >= 256) {
- X *stackp++ = suffix[code];
- X code = prefix[code];
- X }
- X *stackp++ = finchar = suffix[code];
- X
- X /*
- X * And put them out in forward order
- X */
- X do {
- X *outbeg++ = *--stackp;
- X if (outbeg >= outend) {
- X (*output) (outbuf, outbeg-outbuf, t);
- X outbeg = outbuf;
- X }
- X } while (stackp > stack);
- X
- X /*
- X * Generate the new entry.
- X */
- X if ((code = free_ent) < max_maxcode) {
- X prefix[code] = (u_short) oldcode;
- X suffix[code] = finchar;
- X free_ent = code + 1;
- X }
- X /*
- X * Remember previous code.
- X */
- X oldcode = incode;
- X }
- X
- X if (outbeg > outbuf)
- X (*output) (outbuf, outbeg-outbuf, t);
- X}
- X
- X
- X/*************************************************************************
- X * Please note how much trouble it can be to maintain upwards *
- X * compatibility. All that follows is for the sole purpose of unpacking *
- X * files which were packed using an older method. *
- X *************************************************************************/
- X
- X
- X/*
- X * The h() pointer points to the routine to use for calculating a hash value.
- X * It is set in the init routines to point to either of oldh() or newh().
- X *
- X * oldh() calculates a hash value by taking the middle twelve bits of the square
- X * of the key.
- X *
- X * newh() works somewhat differently, and was tried because it makes ARC about
- X * 23% faster. This approach was abandoned because dynamic Lempel-Zev
- X * (above) works as well, and packs smaller also. However, inadvertent
- X * release of a developmental copy forces us to leave this in.
- X */
- X
- static u_short(*h) (); /* pointer to hash function */
- X
- static u_short
- oldh(pred, foll) /* old hash function */
- X u_short pred; /* code for preceeding string */
- X u_char foll; /* value of following char */
- X{
- X long local; /* local hash value */
- X
- X local = ((pred + foll) | 0x0800) & 0xFFFF; /* create the hash key */
- X local *= local; /* square it */
- X return (local >> 6) & 0x0FFF; /* return the middle 12 bits */
- X}
- X
- static u_short
- newh(pred, foll) /* new hash function */
- X u_short pred; /* code for preceeding string */
- X u_char foll; /* value of following char */
- X{
- X return (((pred + foll) & 0xFFFF) * 15073) & 0xFFF; /* faster hash */
- X}
- X
- X/*
- X * The eolist() function is used to trace down a list of entries with
- X * duplicate keys until the last duplicate is found.
- X */
- X
- static u_short
- eolist(index) /* find last duplicate */
- X u_short index;
- X{
- X int temp;
- X
- X while (temp = string_tab[index].next) /* while more duplicates */
- X index = temp;
- X
- X return index;
- X}
- X
- X/*
- X * The hash() routine is used to find a spot in the hash table for a new
- X * entry. It performs a "hash and linear probe" lookup, using h() to
- X * calculate the starting hash value and eolist() to perform the linear
- X * probe. This routine DOES NOT detect a table full condition. That MUST be
- X * checked for elsewhere.
- X */
- X
- static u_short
- hash(pred, foll) /* find spot in the string table */
- X u_short pred; /* code for preceeding string */
- X u_char foll; /* char following string */
- X{
- X u_short local, tempnext; /* scratch storage */
- X struct entry *ep; /* allows faster table handling */
- X
- X local = (*h) (pred, foll); /* get initial hash value */
- X
- X if (!string_tab[local].used) /* if that spot is free */
- X return local; /* then that's all we need */
- X
- X else { /* else a collision has occured */
- X local = eolist(local); /* move to last duplicate */
- X
- X /*
- X * We must find an empty spot. We start looking 101 places
- X * down the table from the last duplicate.
- X */
- X
- X tempnext = (local + 101) & 0x0FFF;
- X ep = &string_tab[tempnext]; /* initialize pointer */
- X
- X while (ep->used) { /* while empty spot not found */
- X if (++tempnext == TABSIZE) { /* if we are at the end */
- X tempnext = 0; /* wrap to beginning of table */
- X ep = string_tab;
- X } else
- X ++ep; /* point to next element in table */
- X }
- X
- X /*
- X * local still has the pointer to the last duplicate, while
- X * tempnext has the pointer to the spot we found. We use
- X * this to maintain the chain of pointers to duplicates.
- X */
- X
- X string_tab[local].next = tempnext;
- X
- X return tempnext;
- X }
- X}
- X
- X/*
- X * The init_tab() routine is used to initialize our hash table. You realize,
- X * of course, that "initialize" is a complete misnomer.
- X */
- X
- static VOID
- init_tab()
- X{ /* set ground state in hash table */
- X unsigned int i; /* table index */
- X
- X setmem((char *) string_tab, TABSIZE * sizeof(struct entry), 0);
- X
- X for (i = 0; i < 256; i++) /* list all single byte strings */
- X upd_tab(NO_PRED, i);
- X}
- X
- X/*
- X * The upd_tab routine is used to add a new entry to the string table. As
- X * previously stated, no checks are made to ensure that the table has any
- X * room. This must be done elsewhere.
- X */
- X
- VOID
- upd_tab(pred, foll) /* add an entry to the table */
- X u_short pred; /* code for preceeding string */
- X u_short foll; /* character which follows string */
- X{
- X struct entry *ep; /* pointer to current entry */
- X
- X /* calculate offset just once */
- X
- X ep = &string_tab[hash(pred, foll)];
- X
- X ep->used = TRUE; /* this spot is now in use */
- X ep->next = 0; /* no duplicates after this yet */
- X ep->predecessor = pred; /* note code of preceeding string */
- X ep->follower = foll; /* note char after string */
- X}
- X
- X/*
- X * This algorithm encoded a file into twelve bit strings (three nybbles). The
- X * gocode() routine is used to read these strings a byte (or two) at a time.
- X */
- X
- X#define GOCODE(x)\
- if ((inflag^=1)) { x = (*inbeg++ << 4); x |= (*inbeg >> 4); } \
- else {x = (*inbeg++ & 0x0f) << 8; x |= (*inbeg++); }
- X
- X/* push char onto stack */
- X#define PUSH(c) \
- do { stack[sp] = ((char) (c)); \
- X if (++sp >= TABSIZE) \
- X arcdie("Stack overflow\n"); \
- X} while (0)
- X
- X/* pop character from stack */
- X#define POP() ((sp > 0) ? (int) stack[--sp] : EMPTY)
- X
- X/***** LEMPEL-ZEV DECOMPRESSION *****/
- X
- static int code_count; /* needed to detect table full */
- static int oldcode, finchar;
- X
- VOID
- init_ucr(new, f) /* get set for uncrunching */
- X int new; /* true to use new hash function */
- X FILE *f; /* input file */
- X{
- X if (new) /* set proper hash function */
- X h = newh;
- X else
- X h = oldh;
- X
- X sp = 0; /* clear out the stack */
- X init_tab(); /* set up atomic code definitions */
- X code_count = TABSIZE - 256; /* note space left in table */
- X inbeg = pinbuf;
- X inend = &inbeg[getb_unp(f)];
- X inflag = 0;
- X GOCODE(oldcode);
- X finchar = string_tab[oldcode].follower;
- X outbeg = outbuf;
- X *outbeg++ = finchar;
- X}
- X
- u_int
- getb_ucr(f) /* get next uncrunched byte */
- X FILE *f; /* file containing crunched data */
- X{
- X int code, newcode;
- X struct entry *ep; /* allows faster table handling */
- X u_int len;
- X
- X do {
- X if (!sp) { /* if stack is empty */
- X if (inbeg >= inend-1) {
- X inbeg = pinbuf;
- X inend = &inbeg[getb_unp(f)];
- X if (inbeg == inend) {
- X break;
- X }
- X }
- X GOCODE(newcode);
- X code = newcode;
- X
- X ep = &string_tab[code]; /* initialize pointer */
- X
- X if (!ep->used) {/* if code isn't known */
- X code = oldcode;
- X ep = &string_tab[code]; /* re-initialize pointer */
- X PUSH(finchar);
- X }
- X while (ep->predecessor != NO_PRED) {
- X PUSH(ep->follower); /* decode string backwards */
- X code = ep->predecessor;
- X ep = &string_tab[code];
- X }
- X
- X PUSH(finchar = ep->follower); /* save first character also */
- X
- X /*
- X * The above loop will terminate, one way or another, with
- X * string_tab[code].follower equal to the first character in
- X * the string.
- X */
- X
- X if (code_count) { /* if room left in string table */
- X upd_tab(oldcode, finchar);
- X --code_count;
- X }
- X oldcode = newcode;
- X }
- X *outbeg++ = POP();
- X } while (outbeg <= outend);
- X len = outbeg - outbuf;
- X outbeg = outbuf;
- X return (len);
- X}
- END_OF_FILE
- if test 22078 -ne `wc -c <'arclzw.c'`; then
- echo shar: \"'arclzw.c'\" unpacked with wrong size!
- fi
- # end of 'arclzw.c'
- fi
- if test -f 'arcmisc.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'arcmisc.c'\"
- else
- echo shar: Extracting \"'arcmisc.c'\" \(8784 characters\)
- sed "s/^X//" >'arcmisc.c' <<'END_OF_FILE'
- X/*
- X * Miscellaneous routines to get ARC running on non-MSDOS systems...
- X * $Header: /var/local/hyc/src/arc/RCS/arcmisc.c,v 2.0 1991/11/12 00:34:06 hyc Exp $
- X */
- X
- X#include <stdio.h>
- X#include <ctype.h>
- X#include "arc.h"
- X
- X#include <string.h>
- X#if BSD
- X#include <strings.h>
- X#endif
- X
- X#if MSDOS
- X#include <dir.h>
- X#include <stat.h>
- X#endif
- X
- X#if GEMDOS
- X#include <types.h>
- X#include <osbind.h>
- X#include <stat.h>
- X
- VOID
- exitpause()
- X{
- X while (Cconis())
- X Cnecin();
- X fprintf(stderr, "Press any key to continue: ");
- X fflush(stderr);
- X Cnecin();
- X fprintf(stderr, "\n");
- X}
- X
- int
- chdir(dirname)
- X char *dirname;
- X{
- X char *i;
- X int drv;
- X
- X i = dirname;
- X if ((i = index(dirname, ':')) != NULL) {
- X drv = i[-1];
- X i++; /* Move past device spec */
- X if (drv > '\'')
- X drv -= 'a';
- X else
- X drv -= 'A';
- X if (drv >= 0 && drv < 16)
- X Dsetdrv(drv);
- X }
- X if (*i != '\0')
- X return (Dsetpath(i));
- X}
- X#endif
- X
- X#if UNIX
- X#include <sys/types.h>
- X#if SYSV
- X#include <dirent.h>
- X#define DIRECT dirent
- X#else
- X#include <sys/dir.h>
- X#define DIRECT direct
- X#endif
- X#include <sys/stat.h>
- X int rename(), unlink();
- X#endif
- X
- X#if NEEDMEMSET
- char *
- memset(s, c, n) /* This came from SVR2? */
- X char *s;
- X int c, n;
- X{
- X register int i;
- X for(i=0;i<n;i++)
- X s[i]=c;
- X return(s);
- X}
- X#else
- X#include <memory.h>
- X#endif
- X
- X#ifndef __STDC__
- char *malloc();
- X#ifndef _AIX
- int free();
- X#endif
- X#endif
- int match();
- X
- int
- move(oldnam, newnam)
- X char *oldnam, *newnam;
- X{
- X FILE *fopen(), *old, *new;
- X#if !_MTS
- X struct stat oldstat;
- X#endif
- X VOID filecopy();
- X#if GEMDOS
- X if (Frename(0, oldnam, newnam))
- X#else
- X if (rename(oldnam, newnam))
- X#endif
- X#if !_MTS
- X {
- X if (stat(oldnam, &oldstat)) /* different partition? */
- X return (-1);
- X old = fopen(oldnam, OPEN_R);
- X if (old == NULL)
- X return (-1);
- X new = fopen(newnam, OPEN_W);
- X if (new == NULL)
- X return (-1);
- X filecopy(old, new, oldstat.st_size);
- X return(unlink(oldnam));
- X }
- X return 0;
- X#else
- X return(-1);
- X#endif
- X}
- X
- static VOID
- X_makefn(source, dest)
- X char *source;
- X char *dest;
- X{
- X int j;
- X#if MSDOS
- X char *setmem();
- X#endif
- X
- X setmem(dest, 17, 0); /* clear result field */
- X for (j = 0; *source && *source != '.'; ++source)
- X if (j < 8)
- X dest[j++] = *source;
- X for (j = 9; *source; ++source)
- X if (j < 13)
- X dest[j++] = *source;
- X}
- X/*
- X * make a file name using a template
- X */
- X
- char *
- makefnam(rawfn, template, result)
- X char *rawfn; /* the original file name */
- X char *template; /* the template data */
- X char *result; /* where to place the result */
- X{
- X char et[17], er[17], rawbuf[STRLEN], *i;
- X
- X *rawbuf = 0;
- X strcpy(rawbuf, rawfn);
- X#if _MTS
- X i = rawbuf;
- X if (rawbuf[0] == tmpchr[0]) {
- X i++;
- X strcpy(rawfn, i);
- X } else
- X#endif
- X if ((i = rindex(rawbuf, CUTOFF))) {
- X i++;
- X strcpy(rawfn, i);
- X }
- X#if DOS
- X else if ((i = rindex(rawbuf, ':'))) {
- X i++;
- X strcpy(rawfn, i);
- X }
- X#endif
- X if (i)
- X *i = 0;
- X else
- X *rawbuf = 0;
- X
- X _makefn(template, et);
- X _makefn(rawfn, er);
- X *result = 0; /* assure no data */
- X strcat(result, rawbuf);
- X strcat(result, er[0] ? er : et);
- X strcat(result, er[9] ? er + 9 : et + 9);
- X return ((char *) &result[0]);
- X}
- X
- X#if MSDOS || SYSV
- X
- int
- alphasort(dirptr1, dirptr2)
- X struct DIRECT **dirptr1, **dirptr2;
- X{
- X return (strcmp((*dirptr1)->d_name, (*dirptr2)->d_name));
- X}
- X
- X#endif
- X
- VOID
- upper(string)
- X char *string;
- X{
- X char *p;
- X
- X for (p = string; *p; p++)
- X if (islower(*p))
- X *p = toupper(*p);
- X}
- X/* VARARGS1 */
- VOID
- arcdie(s, arg1, arg2, arg3)
- X char *s;
- X{
- X fprintf(stderr, "ARC: ");
- X fprintf(stderr, s, arg1, arg2, arg3);
- X fprintf(stderr, "\n");
- X#if UNIX
- X perror("UNIX");
- X#endif
- X#if GEMDOS
- X exitpause();
- X#endif
- X exit(1);
- X}
- X
- X#if !_MTS
- X
- char *
- gcdir(dirname)
- X char *dirname;
- X
- X{
- X char *getwd();
- X#if GEMDOS
- X int drv;
- X char *buf;
- X#endif
- X if (dirname == NULL || strlen(dirname) == 0)
- X dirname = (char *) malloc(1024);
- X
- X#if !GEMDOS
- X getwd(dirname);
- X#else
- X buf = dirname;
- X *buf++ = (drv = Dgetdrv()) + 'A';
- X *buf++ = ':';
- X Dgetpath(buf, 0);
- X#endif
- X return (dirname);
- X}
- X
- X#if UNIX
- char *pattern; /* global so that fmatch can use it */
- X#endif
- X
- char *
- dir(filename) /* get files, one by one */
- X char *filename; /* template, or NULL */
- X{
- X#if GEMDOS
- X static int Nnum = 0;
- X#if __GNUC__
- X#define d_fname dta_name /* Wish these libraries would agree on names */
- X#define DMABUFFER _DTA
- X#endif
- X static DMABUFFER dbuf, *saved;
- X char *name;
- X if (Nnum == 0) { /* first call */
- X saved = (DMABUFFER *) Fgetdta();
- X Fsetdta(&dbuf);
- X if (Fsfirst(filename, 0) == 0) {
- X name = malloc(FNLEN);
- X strcpy(name, dbuf.d_fname);
- X Nnum++;
- X return (name);
- X } else {
- X Fsetdta(saved);
- X return (NULL);
- X }
- X } else {
- X if (Fsnext() == 0) {
- X name = malloc(FNLEN);
- X strcpy(name, dbuf.d_fname);
- X return (name);
- X } else {
- X Nnum = 0;
- X Fsetdta(saved);
- X return (NULL);
- X }
- X }
- X}
- X#else
- X static struct DIRECT **namelist;
- X static char **NameList;
- X static char namecopy[STRLEN], *dirname;
- X#if UNIX
- X int alphasort();
- X int scandir();
- X#endif /* UNIX */
- X int fmatch();
- X static int Nnum = 0, ii;
- X
- X
- X if (Nnum == 0) { /* first call */
- X strcpy(namecopy,filename);
- X if(pattern=rindex(namecopy,CUTOFF)) {
- X *pattern = 0;
- X pattern++;
- X dirname = namecopy;
- X } else {
- X pattern = filename;
- X dirname = ".";
- X }
- X Nnum = scandir(dirname, &namelist, fmatch, alphasort);
- X NameList = (char **) malloc(Nnum * sizeof(char *));
- X for (ii = 0; ii < Nnum; ii++) {
- X (NameList)[ii] = malloc(strlen(namelist[ii]->d_name) + 1);
- X strcpy((NameList)[ii], namelist[ii]->d_name);
- X }
- X ii = 0;
- X }
- X if (ii >= Nnum) { /* all out of files */
- X if (Nnum) { /* there were some files found */
- X for (ii = 0; ii < Nnum; ii++)
- X free(namelist[ii]);
- X free(namelist);
- X }
- X Nnum = 0;
- X return (NULL);
- X } else {
- X return ((NameList)[ii++]);
- X }
- X}
- X
- X/*
- X * Filename match - here, * matches everything
- X */
- X
- int
- fmatch(direntry)
- X struct DIRECT *direntry;
- X{
- X char *string;
- X
- X string = direntry->d_name;
- X
- X if (!strcmp(pattern, "") || !strcmp(pattern, "*.*") || !strcmp(pattern, "*"))
- X return (1);
- X return (match(string, pattern));
- X}
- X#endif /* GEMDOS */
- X#else
- X/* dir code for MTS under Bell Labs C... */
- X
- char *
- dir(filepattern)
- X char *filepattern; /* template or NULL */
- X{
- X#if USECATSCAN
- X fortran VOID catscan(), fileinfo();
- X
- X struct catname {
- X short len;
- X char name[257];
- X } pattern;
- X
- X struct catval {
- X int maxlen;
- X int actlen;
- X char name[257];
- X } catreturn;
- X
- X char *i;
- X int j, RETCODE;
- X
- X static int catptr = 0;
- X static int catflag = 0x200;
- X static int cattype = 1;
- X static int patflag = 0;
- X
- X catreturn.maxlen = 256;
- X
- X if (patflag) {
- X patflag = 0;
- X catptr = 0;
- X return (NULL);
- X }
- X if (filepattern) {
- X strcpy(pattern.name, filepattern);
- X pattern.len = strlen(filepattern);
- X if (!index(filepattern, '?'))
- X patflag = 1;
- X }
- X if (patflag) {
- X fileinfo(&pattern, &cattype, "CINAME ", &catreturn, _retcode RETCODE);
- X catptr = RETCODE ? 0 : 1;
- X } else
- X catscan(&pattern, &catflag, &cattype, &catreturn, &catptr);
- X
- X if (!catptr)
- X return (NULL);
- X else {
- X char *k;
- X
- X/* k = index(catreturn.name, ' ');
- X if (k)
- X *k = 0;
- X else { This seems unnecessary now */
- X j = catreturn.actlen;
- X catreturn.name[j] = 0;
- X/* } */
- X k = catreturn.name;
- X if (*k == tmpchr[0])
- X k++;
- X else if ((k = index(catreturn.name, sepchr[0])))
- X k++;
- X else
- X k = catreturn.name;
- X j = strlen(k);
- X i = malloc(++j);
- X strcpy(i, k);
- X return (i);
- X }
- X#else
- X fortran VOID gfinfo();
- X static char gfname[24];
- X static char pattern[20];
- X static int gfdummy[2] = {
- X 0, 0
- X }, gfflags;
- X int i, RETCODE;
- X char *j, *k;
- X
- X if (filepattern) {
- X strcpy(pattern, filepattern);
- X strcat(pattern, " ");
- X for (i = 20; i < 24; i++)
- X gfname[i] = '\0';
- X if (index(pattern, '?'))
- X gfflags = 0x0C;
- X else
- X gfflags = 0x09;
- X } else if (gfflags == 0x09)
- X return (NULL);
- X
- X gfinfo(pattern, gfname, &gfflags, gfdummy, gfdummy, gfdummy, _retcode RETCODE);
- X if (RETCODE)
- X return (NULL);
- X else {
- X k = index(gfname, ' ');
- X *k = '\0';
- X k = gfname;
- X if (gfname[0] == tmpchr[0])
- X k++;
- X else if ((k = index(gfname, sepchr[0])))
- X k++;
- X else
- X k = gfname;
- X i = strlen(k);
- X j = malloc(++i);
- X strcpy(j, k);
- X return (j);
- X }
- X#endif
- X}
- X
- int
- unlink(path)
- X char *path; /* name of file to delete */
- X{
- X fortran VOID destroy();
- X int RETCODE;
- X
- X char name[258];
- X
- X strcpy(name, path);
- X strcat(name, " ");
- X destroy(name, _retcode RETCODE);
- X if (RETCODE)
- X return (-1);
- X else
- X return (0);
- X}
- X#endif
- END_OF_FILE
- if test 8784 -ne `wc -c <'arcmisc.c'`; then
- echo shar: \"'arcmisc.c'\" unpacked with wrong size!
- fi
- # end of 'arcmisc.c'
- fi
- if test -f 'arcsq.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'arcsq.c'\"
- else
- echo shar: Extracting \"'arcsq.c'\" \(13957 characters\)
- sed "s/^X//" >'arcsq.c' <<'END_OF_FILE'
- X/*
- X * $Header: /var/local/hyc/src/arc/RCS/arcsq.c,v 2.0 1991/11/12 00:30:01 hyc Exp $
- X */
- X
- X/*
- X * ARC - Archive utility - ARCSQ
- X *
- X * Version 3.10, created on 01/30/86 at 20:10:46
- X *
- X * (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED
- X *
- X * By: Thom Henderson
- X *
- X * Description: This file contains the routines used to squeeze a file when
- X * placing it in an archive.
- X *
- X * Language: Computer Innovations Optimizing C86
- X *
- X * Programming notes: Most of the routines used for the Huffman squeezing
- X * algorithm were lifted from the SQ program by Dick Greenlaw, as adapted to
- X * CI-C86 by Robert J. Beilstein.
- X */
- X#include <stdio.h>
- X#include "arc.h"
- X
- X#include "proto.h"
- X
- X/* stuff for Huffman squeezing */
- X
- X#define TRUE 1
- X#define FALSE 0
- X#define ERROR (-1)
- X#define SPEOF 256 /* special endfile token */
- X#define NOCHILD (-1) /* marks end of path through tree */
- X#define NUMVALS 257 /* 256 data values plus SPEOF */
- X#define NUMNODES (NUMVALS+NUMVALS-1) /* number of nodes */
- X#define MAXCOUNT (u_short) 65535/* biggest unsigned integer */
- X
- X/*
- X * The following array of structures are the nodes of the binary trees. The
- X * first NUMVALS nodes become the leaves of the final tree and represent the
- X * values of the data bytes being encoded and the special endfile, SPEOF. The
- X * remaining nodes become the internal nodes of the final tree.
- X */
- X
- struct nd { /* shared by unsqueezer */
- X u_short weight; /* number of appearances */
- X short tdepth; /* length on longest path in tree */
- X short lchild, rchild; /* indices to next level */
- X} node[NUMNODES]; /* use large buffer */
- X
- static int dctreehd; /* index to head of final tree */
- X
- X/*
- X * This is the encoding table: The bit strings have first bit in low bit.
- X * Note that counts were scaled so code fits unsigned integer.
- X */
- X
- static int codelen[NUMVALS]; /* number of bits in code */
- static u_short code[NUMVALS]; /* code itself, right adjusted */
- static u_short tcode; /* temporary code value */
- static long valcount[NUMVALS]; /* actual count of times seen */
- X
- X/* Variables used by encoding process */
- X
- int curin; /* value currently being encoded */
- static int cbitsrem; /* # of code string bits left */
- static u_short ccode; /* current code right justified */
- X
- static VOID scale(), heap(), adjust(), bld_tree(), init_enc();
- static int cmptrees(), buildenc();
- X
- extern u_char outbuf[], *outbeg, *outend;
- X
- VOID
- init_sq()
- X{ /* prepare for scanning pass */
- X int i; /* node index */
- X
- X /*
- X * Initialize all nodes to single element binary trees with zero
- X * weight and depth.
- X */
- X
- X for (i = 0; i < NUMNODES; ++i) {
- X node[i].weight = 0;
- X node[i].tdepth = 0;
- X node[i].lchild = NOCHILD;
- X node[i].rchild = NOCHILD;
- X }
- X
- X for (i = 0; i < NUMVALS; i++)
- X valcount[i] = 0;
- X}
- X
- VOID
- hufb_tab(buf, len) /* add a byte to the tables */
- X u_char *buf;
- X u_int len;
- X{
- X for (; len > 0; len--) {
- X
- X /* Build frequency info in tree */
- X
- X if (node[*buf].weight != MAXCOUNT)
- X node[*buf].weight++; /* bump weight counter */
- X
- X valcount[*buf++]++; /* bump byte counter */
- X }
- X}
- X
- long
- pred_sq()
- X{ /* predict size of squeezed file */
- X int i;
- X int btlist[NUMVALS]; /* list of intermediate
- X * b-trees */
- X int listlen;/* length of btlist */
- X u_short ceiling;/* limit for scaling */
- X long size = 0; /* predicted size */
- X int numnodes; /* # of nodes in simplified tree */
- X
- X node[SPEOF].weight = 1; /* signal end of input */
- X valcount[SPEOF] = 1;
- X
- X ceiling = MAXCOUNT;
- X
- X /* Keep trying to scale and encode */
- X
- X do {
- X scale(ceiling);
- X ceiling /= 2; /* in case we rescale */
- X
- X /*
- X * Build list of single node binary trees having leaves for
- X * the input values with non-zero counts
- X */
- X
- X for (i = listlen = 0; i < NUMVALS; ++i) {
- X if (node[i].weight != 0) {
- X node[i].tdepth = 0;
- X btlist[listlen++] = i;
- X }
- X }
- X
- X /*
- X * Arrange list of trees into a heap with the entry indexing
- X * the node with the least weight at the top.
- X */
- X
- X heap(btlist, listlen);
- X
- X /* Convert the list of trees to a single decoding tree */
- X
- X bld_tree(btlist, listlen);
- X
- X /* Initialize the encoding table */
- X
- X init_enc();
- X
- X /*
- X * Try to build encoding table. Fail if any code is > 16 bits
- X * long.
- X */
- X } while (buildenc(0, dctreehd) == ERROR);
- X
- X /* Initialize encoding variables */
- X
- X cbitsrem = 0; /* force initial read */
- X curin = 0; /* anything but endfile */
- X
- X for (i = 0; i < NUMVALS; i++) /* add bits for each code */
- X size += valcount[i] * codelen[i];
- X
- X size = (size + 7) / 8; /* reduce to number of bytes */
- X
- X numnodes = dctreehd < NUMVALS ? 0 : dctreehd - (NUMVALS - 1);
- X
- X size += sizeof(short) + 2 * numnodes * sizeof(short);
- X
- X return size;
- X}
- X
- X/*
- X * The count of number of occurrances of each input value have already been
- X * prevented from exceeding MAXCOUNT. Now we must scale them so that their
- X * sum doesn't exceed ceiling and yet no non-zero count can become zero. This
- X * scaling prevents errors in the weights of the interior nodes of the
- X * Huffman tree and also ensures that the codes will fit in an unsigned
- X * integer. Rescaling is used if necessary to limit the code length.
- X */
- X
- static VOID
- scale(ceil)
- X u_short ceil; /* upper limit on total weight */
- X{
- X register int i;
- X int ovflw, divisor;
- X u_short w, sum;
- X unsigned char increased; /* flag */
- X
- X do {
- X for (i = sum = ovflw = 0; i < NUMVALS; ++i) {
- X if (node[i].weight > (ceil - sum))
- X ++ovflw;
- X sum += node[i].weight;
- X }
- X
- X divisor = ovflw + 1;
- X
- X /* Ensure no non-zero values are lost */
- X
- X increased = FALSE;
- X for (i = 0; i < NUMVALS; ++i) {
- X w = node[i].weight;
- X if (w < divisor && w != 0) { /* Don't fail to provide
- X * a code if it's used
- X * at all */
- X
- X node[i].weight = divisor;
- X increased = TRUE;
- X }
- X }
- X } while (increased);
- X
- X /* Scaling factor chosen, now scale */
- X
- X if (divisor > 1)
- X for (i = 0; i < NUMVALS; ++i)
- X node[i].weight /= divisor;
- X}
- X
- X/*
- X * heap() and adjust() maintain a list of binary trees as a heap with the top
- X * indexing the binary tree on the list which has the least weight or, in
- X * case of equal weights, least depth in its longest path. The depth part is
- X * not strictly necessary, but tends to avoid long codes which might provoke
- X * rescaling.
- X */
- X
- static VOID
- heap(list, length)
- X int list[], length;
- X{
- X register int i;
- X
- X for (i = (length - 2) / 2; i >= 0; --i)
- X adjust(list, i, length - 1);
- X}
- X
- X/* Make a heap from a heap with a new top */
- X
- static VOID
- adjust(list, top, bottom)
- X int list[], top, bottom;
- X{
- X register int k, temp;
- X
- X k = 2 * top + 1; /* left child of top */
- X temp = list[top]; /* remember root node of top tree */
- X
- X if (k <= bottom) {
- X if (k < bottom && cmptrees(list[k], list[k + 1]))
- X ++k;
- X
- X /* k indexes "smaller" child (in heap of trees) of top */
- X /* now make top index "smaller" of old top and smallest child */
- X
- X if (cmptrees(temp, list[k])) {
- X list[top] = list[k];
- X list[k] = temp;
- X
- X /* Make the changed list a heap */
- X
- X adjust(list, k, bottom); /* recursive */
- X }
- X }
- X}
- X
- X/*
- X * Compare two trees, if a > b return true, else return false. Note
- X * comparison rules in previous comments.
- X */
- X
- static int
- cmptrees(a, b)
- X int a, b; /* root nodes of trees */
- X{
- X if (node[a].weight > node[b].weight)
- X return TRUE;
- X if (node[a].weight == node[b].weight)
- X if (node[a].tdepth > node[b].tdepth)
- X return TRUE;
- X return FALSE;
- X}
- X
- X/*
- X * HUFFMAN ALGORITHM: develops the single element trees into a single binary
- X * tree by forming subtrees rooted in interior nodes having weights equal to
- X * the sum of weights of all their descendents and having depth counts
- X * indicating the depth of their longest paths.
- X *
- X * When all trees have been formed into a single tree satisfying the heap
- X * property (on weight, with depth as a tie breaker) then the binary code
- X * assigned to a leaf (value to be encoded) is then the series of left (0)
- X * and right (1) paths leading from the root to the leaf. Note that trees are
- X * removed from the heaped list by moving the last element over the top
- X * element and reheaping the shorter list.
- X */
- X
- X#define MAXCHAR(a,b) ((a > b) ? a : b)
- X
- static VOID
- bld_tree(list, len)
- X int list[];
- X int len;
- X{
- X register int freenode; /* next free node in tree */
- X register struct nd *frnp; /* free node pointer */
- X int lch, rch; /* temps for left, right children */
- X
- X /*
- X * Initialize index to next available (non-leaf) node. Lower numbered
- X * nodes correspond to leaves (data values).
- X */
- X
- X freenode = NUMVALS;
- X
- X while (len > 1) { /* Take from list two btrees with least
- X * weight and build an interior node pointing
- X * to them. This forms a new tree. */
- X
- X lch = list[0]; /* This one will be left child */
- X
- X /* delete top (least) tree from the list of trees */
- X
- X list[0] = list[--len];
- X adjust(list, 0, len - 1);
- X
- X /* Take new top (least) tree. Reuse list slot later */
- X
- X rch = list[0]; /* This one will be right child */
- X
- X /*
- X * Form new tree from the two least trees using a free node
- X * as root. Put the new tree in the list.
- X */
- X
- X frnp = &node[freenode]; /* address of next free node */
- X list[0] = freenode++; /* put at top for now */
- X frnp->lchild = lch;
- X frnp->rchild = rch;
- X frnp->weight = node[lch].weight + node[rch].weight;
- X frnp->tdepth = 1 + MAXCHAR(node[lch].tdepth, node[rch].tdepth);
- X
- X /* reheap list to get least tree at top */
- X
- X adjust(list, 0, len - 1);
- X }
- X dctreehd = list[0]; /* head of final tree */
- X}
- X
- static VOID
- init_enc()
- X{
- X register int i;
- X
- X /* Initialize encoding table */
- X
- X for (i = 0; i < NUMVALS; ++i)
- X codelen[i] = 0;
- X}
- X
- X/*
- X * Recursive routine to walk the indicated subtree and level and maintain the
- X * current path code in bstree. When a leaf is found the entire code string
- X * and length are put into the encoding table entry for the leaf's data value.
- X *
- X * Returns ERROR if codes are too long.
- X */
- X
- static int
- buildenc(level, root)
- X int level; /* level of tree being examined, from zero */
- X int root; /* root of subtree is also data value if leaf */
- X{
- X register int l, r;
- X
- X l = node[root].lchild;
- X r = node[root].rchild;
- X
- X if (l == NOCHILD && r == NOCHILD) { /* Leaf. Previous path
- X * determines bit string code
- X * of length level (bits 0 to
- X * level - 1). Ensures unused
- X * code bits are zero. */
- X
- X codelen[root] = level;
- X code[root] = tcode & (((u_short) ~ 0) >> (16 - level));
- X return (level > 16) ? ERROR : 0;
- X } else {
- X if (l != NOCHILD) { /* Clear path bit and continue deeper */
- X
- X tcode &= ~(1 << level);
- X if (buildenc(level + 1, l) == ERROR)
- X return ERROR; /* pass back bad statuses */
- X }
- X if (r != NOCHILD) { /* Set path bit and continue deeper */
- X
- X tcode |= 1 << level;
- X if (buildenc(level + 1, r) == ERROR)
- X return ERROR; /* pass back bad statuses */
- X }
- X }
- X return 0; /* it worked if we reach here */
- X}
- X
- X#define OUT_INT(n) \
- X *outbeg++ = n & 0xff; /* first the low byte */ \
- X *outbeg++ = n >> 8; /* then the high byte */
- X
- X/* Write out the header of the compressed file */
- X
- long
- head_sq()
- X{
- X register int l, r;
- X int i, k;
- X int numnodes; /* # of nodes in simplified tree */
- X
- X outbeg = outbuf;
- X
- X /*
- X * Write out a simplified decoding tree. Only the interior nodes are
- X * written. When a child is a leaf index (representing a data value)
- X * it is recoded as -(index + 1) to distinguish it from interior
- X * indexes which are recoded as positive indexes in the new tree.
- X *
- X * Note that this tree will be empty for an empty file.
- X */
- X
- X numnodes = dctreehd < NUMVALS ? 0 : dctreehd - (NUMVALS - 1);
- X OUT_INT(numnodes)
- X for (k = 0, i = dctreehd; k < numnodes; ++k, --i) {
- X l = node[i].lchild;
- X r = node[i].rchild;
- X l = l < NUMVALS ? -(l + 1) : dctreehd - l;
- X r = r < NUMVALS ? -(r + 1) : dctreehd - r;
- X OUT_INT(l)
- X OUT_INT(r)
- X }
- X
- X return sizeof(short) + numnodes * 2 * sizeof(short);
- X}
- X
- X/*
- X * This routine is used to perform the actual squeeze operation. It can only
- X * be called after the file has been scanned. It returns the true length of
- X * the squeezed entry.
- X *
- X * There are two unsynchronized bit-byte relationships here. The input stream
- X * bytes are converted to bit strings of various lengths via the static
- X * variables named c... These bit strings are concatenated without padding to
- X * become the stream of encoded result bytes, which this function returns one
- X * at a time. The EOF (end of file) is converted to SPEOF for convenience and
- X * encoded like any other input value. True EOF is returned after that.
- X */
- X
- long
- huf_buf(pbuf, plen, len, ob)
- X u_char *pbuf; /* ncr'd input buffer */
- X u_int plen; /* length of pack buffer */
- X u_int len; /* length of input buffer */
- X FILE *ob; /* output file */
- X{
- X int rbyte; /* Result byte value */
- X int need; /* number of bits */
- X long size = 0;
- X
- X if (len == 0) /* Account for EOF/SPEOF */
- X plen++;
- X
- X while (plen != 0) {
- X if (outbeg > outend) {
- X putb_pak(outbuf, (u_int) (outbeg-outbuf), ob);
- X outbeg = outbuf;
- X }
- X rbyte = 0;
- X need = 8; /* build one byte per call */
- X
- X /*
- X * Loop to build a byte of encoded data.
- X */
- X
- loop:
- X if (cbitsrem >= need) { /* if current code is big enough */
- X if (need == 0) {
- X *outbeg++ = rbyte;
- X size++;
- X continue;
- X }
- X rbyte |= ccode << (8 - need); /* take what we need */
- X ccode >>= need; /* and leave the rest */
- X cbitsrem -= need;
- X *outbeg++ = rbyte & 0xff;
- X size++;
- X continue;
- X }
- X /* We need more than current code */
- X
- X if (cbitsrem > 0) {
- X rbyte |= ccode << (8 - need); /* take what there is */
- X need -= cbitsrem;
- X }
- X /* No more bits in current code string */
- X
- X if (curin == SPEOF) { /* The end of file token has been
- X * encoded. Save result byte. */
- X cbitsrem = 0;
- X if (need != 8) {
- X *outbeg++ = rbyte;
- X size++;
- X }
- X break;
- X }
- X /* Get an input byte */
- X
- X if (plen == 1 && len == 0)
- X curin = SPEOF; /* convenient for encoding */
- X else
- X curin = *pbuf++;
- X plen--;
- X
- X ccode = code[curin]; /* get the new byte's code */
- X cbitsrem = codelen[curin];
- X
- X goto loop;
- X }
- X if (len == 0)
- X putb_pak(outbuf, (u_int) (outbeg - outbuf), ob);
- X return (size);
- X}
- END_OF_FILE
- if test 13957 -ne `wc -c <'arcsq.c'`; then
- echo shar: \"'arcsq.c'\" unpacked with wrong size!
- fi
- # end of 'arcsq.c'
- fi
- if test -f 'marc.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'marc.c'\"
- else
- echo shar: Extracting \"'marc.c'\" \(9470 characters\)
- sed "s/^X//" >'marc.c' <<'END_OF_FILE'
- X/*
- X * $Header: /var/local/hyc/src/arc/RCS/marc.c,v 2.0 1991/11/12 00:39:44 hyc Exp $
- X */
- X
- X/* MARC - Archive merge utility
- X
- X Version 5.21, created on 04/22/87 at 15:05:10
- X
- X(C) COPYRIGHT 1985-87 by System Enhancement Associates; ALL RIGHTS RESERVED
- X
- X By: Thom Henderson
- X
- X Description:
- X This program is used to "merge" archives. That is, to move
- X files from one archive to another with no data conversion.
- X Please refer to the ARC source for a description of archives
- X and archive formats.
- X
- X Instructions:
- X Run this program with no arguments for complete instructions.
- X
- X Language:
- X Computer Innovations Optimizing C86
- X*/
- X#include <stdio.h>
- X#include "arc.h"
- X
- X#if UNIX
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#endif
- X
- X#ifndef __STDC__
- char *calloc(), *malloc(), *realloc(); /* memory managers */
- X#endif
- VOID arcdie();
- static VOID expandlst(), merge();
- X
- XFILE *src; /* source archive */
- char srcname[STRLEN]; /* source archive name */
- X
- static char **lst; /* files list */
- static int lnum; /* length of files list */
- X
- int
- main(nargs,arg) /* system entry point */
- int nargs; /* number of arguments */
- char *arg[]; /* pointers to arguments */
- X{
- X char *makefnam(); /* filename fixup routine */
- X char *envfind();
- X#if !_MTS
- X char *arctemp2, *mktemp(); /* temp file stuff */
- X#endif
- X#if GEMDOS
- X VOID exitpause();
- X#endif
- X int n; /* index */
- X#if UNIX
- X struct stat sbuf;
- X#endif
- X
- X
- X if(nargs<3)
- X { printf("MARC - Archive merger, Version 5.21, created on 04/22/87 at 15:05:10\n");
- X/* printf("(C) COPYRIGHT 1985,86,87 by System Enhancement Associates;");
- X printf(" ALL RIGHTS RESERVED\n\n");
- X printf("Please refer all inquiries to:\n\n");
- X printf(" System Enhancement Associates\n");
- X printf(" 21 New Street, Wayne NJ 07470\n\n");
- X printf("You may copy and distribute this program freely,");
- X printf(" provided that:\n");
- X printf(" 1) No fee is charged for such copying and");
- X printf(" distribution, and\n");
- X printf(" 2) It is distributed ONLY in its original,");
- X printf(" unmodified state.\n\n");
- X printf("If you like this program, and find it of use, then your");
- X printf(" contribution will\n");
- X printf("be appreciated. You may not use this product in a");
- X printf(" commercial environment\n");
- X printf("or a governmental organization without paying a license");
- X printf(" fee of $35. Site\n");
- X printf("licenses and commercial distribution licenses are");
- X printf(" available. A program\n");
- X printf("disk and printed documentation are available for $50.\n");
- X printf("\nIf you fail to abide by the terms of this license, ");
- X printf(" then your conscience\n");
- X printf("will haunt you for the rest of your life.\n\n");
- X*/
- X printf("Usage: MARC <tgtarc> <srcarc> [<filename> . . .]\n");
- X printf("Where: <tgtarc> is the archive to add files to,\n");
- X printf(" <srcarc> is the archive to get files from, and\n");
- X printf(" <filename> is zero or more file names to get.\n");
- X printf("\nAdapted from MSDOS by Howard Chu\n");
- X#if GEMDOS
- X exitpause();
- X#endif
- X return 1;
- X }
- X
- X /* see where temp files go */
- X#if !_MTS
- X arctemp = calloc(1, STRLEN);
- X if (!(arctemp2 = envfind("ARCTEMP")))
- X arctemp2 = envfind("TMPDIR");
- X if (arctemp2) {
- X strcpy(arctemp, arctemp2);
- X n = strlen(arctemp);
- X if (arctemp[n - 1] != CUTOFF)
- X arctemp[n] = CUTOFF;
- X }
- X#if UNIX
- X else strcpy(arctemp, "/tmp/");
- X#endif
- X#if !MSDOS
- X {
- X static char tempname[] = "AXXXXXX";
- X strcat(arctemp, mktemp(tempname));
- X }
- X#else
- X strcat(arctemp, "$ARCTEMP");
- X#endif
- X#else
- X guinfo("SHFSEP ", gotinf);
- X sepchr[0] = gotinf[0];
- X guinfo("SCRFCHAR", gotinf);
- X tmpchr[0] = gotinf[0];
- X arctemp = "-$$$";
- X arctemp[0] = tmpchr[0];
- X#endif
- X
- X#if UNIX
- X if (!stat(arg[1],&sbuf))
- X strcpy(arcname,arg[1]);
- X else
- X makefnam(arg[1],".arc",arcname);
- X if (!stat(arg[2],&sbuf))
- X strcpy(srcname,arg[2]);
- X else
- X makefnam(arg[2],".arc",srcname);
- X#else
- X makefnam(arg[1],".ARC",arcname); /* fix up archive names */
- X makefnam(arg[2],".ARC",srcname);
- X/* makefnam(".$$$",arcname,newname);*/
- X#endif
- X sprintf(newname,"%s.arc",arctemp);
- X
- X arc = fopen(arcname,OPEN_R); /* open the archives */
- X if(!(src=fopen(srcname,OPEN_R)))
- X arcdie("Cannot read source archive %s",srcname);
- X if(!(new=fopen(newname,OPEN_W)))
- X arcdie("Cannot create new archive %s",newname);
- X
- X if(!arc)
- X printf("Creating new archive %s\n",arcname);
- X
- X /* get the files list set up */
- X
- X lnum = nargs-3; /* initial length of list */
- X if(lnum<1) /* phoney for default case */
- X { lnum = 1;
- X lst = (char **) calloc(1,sizeof(char *));
- X lst[0] = "*.*";
- X }
- X else /* else use filenames given */
- X { lst = (char **) calloc(lnum,sizeof(char *));
- X for(n=3; n<nargs; n++)
- X lst[n-3] = arg[n];
- X
- X for(n=0; n<lnum; ) /* expand indirect references */
- X { if(*lst[n] == '@')
- X expandlst(n);
- X else n++;
- X }
- X }
- X
- X merge(lnum,lst); /* merge desired files */
- X
- X if(arc) fclose(arc); /* close the archives */
- X fclose(src);
- X fclose(new);
- X
- X if(arc) /* make the switch */
- X if(unlink(arcname))
- X arcdie("Unable to delete old copy of %s",arcname);
- X if(move(newname,arcname))
- X arcdie("Unable to rename %s to %s",newname,arcname);
- X
- X setstamp(arcname,arcdate,arctime); /* new arc matches newest file */
- X
- X#if GEMDOS
- X exitpause();
- X#endif
- X return nerrs;
- X}
- X
- static VOID
- merge(nargs,arg) /* merge two archives */
- int nargs; /* number of filename templates */
- char *arg[]; /* pointers to names */
- X{
- X struct heads srch; /* source archive header */
- X struct heads arch; /* target archive header */
- X int gotsrc, gotarc; /* archive entry versions (0=end) */
- X int copy; /* true to copy file from source */
- X int n; /* index */
- X
- X gotsrc = gethdr(src,&srch); /* get first source file */
- X gotarc = gethdr(arc,&arch); /* get first target file */
- X
- X while(gotsrc || gotarc) /* while more to merge */
- X { if(strcmp(srch.name,arch.name)>0)
- X { copyfile(arc,&arch,gotarc);
- X gotarc = gethdr(arc,&arch);
- X }
- X
- X else if(strcmp(srch.name,arch.name)<0)
- X { copy = 0;
- X for(n=0; n<nargs; n++)
- X { if(match(srch.name,arg[n]))
- X { copy = 1;
- X break;
- X }
- X }
- X if(copy) /* select source or target */
- X { printf("Adding file: %s\n",srch.name);
- X copyfile(src,&srch,gotsrc);
- X }
- X else fseek(src,srch.size,1);
- X gotsrc = gethdr(src,&srch);
- X }
- X
- X else /* duplicate names */
- X { copy = 0;
- X { if((srch.date>arch.date)
- X || (srch.date==arch.date && srch.time>arch.time))
- X { for(n=0; n<nargs; n++)
- X { if(match(srch.name,arg[n]))
- X { copy = 1;
- X break;
- X }
- X }
- X }
- X }
- X if(copy) /* select source or target */
- X { printf("Updating file: %s\n",srch.name);
- X copyfile(src,&srch,gotsrc);
- X gotsrc = gethdr(src,&srch);
- X if(gotarc)
- X { fseek(arc,arch.size,1);
- X gotarc = gethdr(arc,&arch);
- X }
- X }
- X else
- X { copyfile(arc,&arch,gotarc);
- X gotarc = gethdr(arc,&arch);
- X if(gotsrc)
- X { fseek(src,srch.size,1);
- X gotsrc = gethdr(src,&srch);
- X }
- X }
- X }
- X }
- X
- X hdrver = 0; /* end of archive marker */
- X writehdr(&arch,new); /* mark the end of the archive */
- X}
- X
- int gethdr(f,hdr) /* special read header for merge */
- XFILE *f; /* file to read from */
- struct heads *hdr; /* storage for header */
- X{
- X char *i = hdr->name; /* string index */
- X int n; /* index */
- X
- X for(n=0; n<FNLEN; n++) /* fill name field */
- X *i++ = 0176; /* impossible high value */
- X *--i = '\0'; /* properly end the name */
- X
- X hdrver = 0; /* reset header version */
- X if(readhdr(hdr,f)) /* use normal reading logic */
- X return hdrver; /* return the version */
- X else return 0; /* or fake end of archive */
- X}
- X
- copyfile(f,hdr,ver) /* copy a file from an archive */
- XFILE *f; /* archive to copy from */
- struct heads *hdr; /* header data for file */
- int ver; /* header version */
- X{
- X hdrver = ver; /* set header version */
- X writehdr(hdr,new); /* write out the header */
- X filecopy(f,new,hdr->size); /* copy over the data */
- X}
- X
- static VOID
- expandlst(n) /* expand an indirect reference */
- int n; /* number of entry to expand */
- X{
- X FILE *lf, *fopen(); /* list file, opener */
- X char buf[100]; /* input buffer */
- X int x; /* index */
- X char *p = lst[n]+1; /* filename pointer */
- X
- X if(*p) /* use name if one was given */
- X { makefnam(p,".CMD",buf);
- X upper(buf);
- X if(!(lf=fopen(buf,"r")))
- X arcdie("Cannot read list of files in %s",buf);
- X }
- X else lf = stdin; /* else use standard input */
- X
- X for(x=n+1; x<lnum; x++) /* drop reference from the list */
- X lst[x-1] = lst[x];
- X lnum--;
- X
- X while(fscanf(lf,"%99s",buf)>0) /* read in the list */
- X { if(!(lst=(char **) realloc(lst,(lnum+1)*sizeof(char *))))
- X arcdie("too many file references");
- X
- X lst[lnum] = malloc(strlen(buf)+1);
- X strcpy(lst[lnum],buf); /* save the name */
- X lnum++;
- X }
- X
- X if(lf!=stdin) /* avoid closing standard input */
- X fclose(lf);
- X}
- END_OF_FILE
- if test 9470 -ne `wc -c <'marc.c'`; then
- echo shar: \"'marc.c'\" unpacked with wrong size!
- fi
- # end of 'marc.c'
- fi
- echo shar: End of archive 2 \(of 3\).
- cp /dev/null ark2isdone
- MISSING=""
- for I in 1 2 3 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 3 archives.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-